/* 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, 2005, 2006, 2007, 2008, 2009
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
This file is part of GCC.
#include "coretypes.h"
#include "tm.h"
#include "machmode.h"
-#include "real.h"
#include "rtl.h"
#include "tree.h"
#include "flags.h"
#include "output.h"
#include "typeclass.h"
#include "toplev.h"
-#include "ggc.h"
#include "langhooks.h"
#include "intl.h"
#include "tm_p.h"
< (unsigned int) MOVE_RATIO (optimize_insn_for_speed_p ()))
#endif
-/* 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 sets. */
-enum insn_code setmem_optab[NUM_MACHINE_MODES];
-
-/* 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_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
/* Try converting directly if the insn is supported. */
- code = convert_optab_handler (tab, to_mode, from_mode)->insn_code;
+ code = convert_optab_handler (tab, to_mode, from_mode);
if (code != CODE_FOR_nothing)
{
emit_unop_insn (code, to, from,
enum machine_mode full_mode
= smallest_mode_for_size (GET_MODE_BITSIZE (to_mode), MODE_INT);
- gcc_assert (convert_optab_handler (trunc_optab, to_mode, full_mode)->insn_code
+ gcc_assert (convert_optab_handler (trunc_optab, to_mode, full_mode)
!= CODE_FOR_nothing);
if (full_mode != from_mode)
from = convert_to_mode (full_mode, from, unsignedp);
- emit_unop_insn (convert_optab_handler (trunc_optab, to_mode, full_mode)->insn_code,
+ emit_unop_insn (convert_optab_handler (trunc_optab, to_mode, full_mode),
to, from, UNKNOWN);
return;
}
enum machine_mode full_mode
= smallest_mode_for_size (GET_MODE_BITSIZE (from_mode), MODE_INT);
- gcc_assert (convert_optab_handler (sext_optab, full_mode, from_mode)->insn_code
+ gcc_assert (convert_optab_handler (sext_optab, full_mode, from_mode)
!= CODE_FOR_nothing);
if (to_mode == full_mode)
{
- emit_unop_insn (convert_optab_handler (sext_optab, full_mode, from_mode)->insn_code,
+ emit_unop_insn (convert_optab_handler (sext_optab, full_mode,
+ from_mode),
to, from, UNKNOWN);
return;
}
new_from = gen_reg_rtx (full_mode);
- emit_unop_insn (convert_optab_handler (sext_optab, full_mode, from_mode)->insn_code,
+ emit_unop_insn (convert_optab_handler (sext_optab, full_mode, from_mode),
new_from, from, UNKNOWN);
/* else proceed to integer conversions below. */
}
/* Support special truncate insns for certain modes. */
- if (convert_optab_handler (trunc_optab, to_mode, from_mode)->insn_code != CODE_FOR_nothing)
+ if (convert_optab_handler (trunc_optab, to_mode,
+ from_mode) != CODE_FOR_nothing)
{
- emit_unop_insn (convert_optab_handler (trunc_optab, to_mode, from_mode)->insn_code,
+ emit_unop_insn (convert_optab_handler (trunc_optab, to_mode, from_mode),
to, from, UNKNOWN);
return;
}
&& GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT
&& CONST_INT_P (x) && INTVAL (x) < 0)
{
- HOST_WIDE_INT val = INTVAL (x);
+ double_int val = uhwi_to_double_int (INTVAL (x));
- if (oldmode != VOIDmode
- && HOST_BITS_PER_WIDE_INT > GET_MODE_BITSIZE (oldmode))
- {
- int width = GET_MODE_BITSIZE (oldmode);
+ /* We need to zero extend VAL. */
+ if (oldmode != VOIDmode)
+ val = double_int_zext (val, GET_MODE_BITSIZE (oldmode));
- /* We need to zero extend VAL. */
- val &= ((HOST_WIDE_INT) 1 << width) - 1;
- }
-
- return immed_double_const (val, (HOST_WIDE_INT) 0, mode);
+ return immed_double_int_const (val, mode);
}
/* We can do this with a gen_lowpart if both desired and current modes
if (mode == VOIDmode)
break;
- icode = optab_handler (mov_optab, mode)->insn_code;
+ icode = optab_handler (mov_optab, mode);
if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
move_by_pieces_1 (GEN_FCN (icode), mode, &data);
if (mode == VOIDmode)
break;
- icode = optab_handler (mov_optab, mode)->insn_code;
+ icode = optab_handler (mov_optab, mode);
if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
n_insns += l / GET_MODE_SIZE (mode), l %= GET_MODE_SIZE (mode);
}
align = MIN (MEM_ALIGN (x), MEM_ALIGN (y));
+ gcc_assert (align >= BITS_PER_UNIT);
gcc_assert (MEM_P (x));
gcc_assert (MEM_P (y));
an outgoing argument. */
#if defined (REG_PARM_STACK_SPACE)
fn = emit_block_move_libcall_fn (false);
+ /* Avoid set but not used warning if *REG_PARM_STACK_SPACE doesn't
+ depend on its argument. */
+ (void) fn;
if (OUTGOING_REG_PARM_STACK_SPACE ((!fn ? NULL_TREE : TREE_TYPE (fn)))
&& REG_PARM_STACK_SPACE (fn) != 0)
return false;
for ( ; arg != void_list_node ; arg = TREE_CHAIN (arg))
{
enum machine_mode mode = TYPE_MODE (TREE_VALUE (arg));
- rtx tmp = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1);
+ rtx tmp = targetm.calls.function_arg (&args_so_far, mode,
+ NULL_TREE, true);
if (!tmp || !REG_P (tmp))
return false;
if (targetm.calls.arg_partial_bytes (&args_so_far, mode, NULL, 1))
return false;
- FUNCTION_ARG_ADVANCE (args_so_far, mode, NULL_TREE, 1);
+ targetm.calls.function_arg_advance (&args_so_far, mode,
+ NULL_TREE, true);
}
}
return true;
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
{
- enum insn_code code = movmem_optab[(int) mode];
+ enum insn_code code = direct_optab_handler (movmem_optab, mode);
insn_operand_predicate_fn pred;
if (code != CODE_FOR_nothing
if (len == 0)
return 1;
- if (! (memsetp
+ if (! (memsetp
? SET_BY_PIECES_P (len, align)
: STORE_BY_PIECES_P (len, align)))
return 0;
if (mode == VOIDmode)
break;
- icode = optab_handler (mov_optab, mode)->insn_code;
+ icode = optab_handler (mov_optab, mode);
if (icode != CODE_FOR_nothing
&& align >= GET_MODE_ALIGNMENT (mode))
{
if (mode == VOIDmode)
break;
- icode = optab_handler (mov_optab, mode)->insn_code;
+ icode = optab_handler (mov_optab, mode);
if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
store_by_pieces_2 (GEN_FCN (icode), mode, data);
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
{
- enum insn_code code = setmem_optab[(int) mode];
+ enum insn_code code = direct_optab_handler (setmem_optab, mode);
insn_operand_predicate_fn pred;
if (code != CODE_FOR_nothing
return NULL_RTX;
/* The target must support moves in this mode. */
- code = optab_handler (mov_optab, imode)->insn_code;
+ code = optab_handler (mov_optab, imode);
if (code == CODE_FOR_nothing)
return NULL_RTX;
/* Move floating point as parts. */
if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
- && optab_handler (mov_optab, GET_MODE_INNER (mode))->insn_code != CODE_FOR_nothing)
+ && optab_handler (mov_optab, GET_MODE_INNER (mode)) != CODE_FOR_nothing)
try_int = false;
/* Not possible if the values are inherently not adjacent. */
else if (GET_CODE (x) == CONCAT || GET_CODE (y) == CONCAT)
/* Assume all MODE_CC modes are equivalent; if we have movcc, use it. */
if (mode != CCmode)
{
- enum insn_code code = optab_handler (mov_optab, CCmode)->insn_code;
+ enum insn_code code = optab_handler (mov_optab, CCmode);
if (code != CODE_FOR_nothing)
{
x = emit_move_change_mode (CCmode, mode, x, true);
gcc_assert ((unsigned int) mode < (unsigned int) MAX_MACHINE_MODE);
- code = optab_handler (mov_optab, mode)->insn_code;
+ code = optab_handler (mov_optab, mode);
if (code != CODE_FOR_nothing)
return emit_insn (GEN_FCN (code) (x, y));
stack_pointer_delta += PUSH_ROUNDING (GET_MODE_SIZE (mode));
/* If there is push pattern, use it. Otherwise try old way of throwing
MEM representing push operation to move expander. */
- icode = optab_handler (push_optab, mode)->insn_code;
+ icode = optab_handler (push_optab, mode);
if (icode != CODE_FOR_nothing)
{
if (((pred = insn_data[(int) icode].operand[0].predicate)
an array element in an unaligned packed structure field, has the same
problem. */
if (handled_component_p (to)
+ /* ??? We only need to handle MEM_REF here if the access is not
+ a full access of the base object. */
+ || (TREE_CODE (to) == MEM_REF
+ && TREE_CODE (TREE_OPERAND (to, 0)) == ADDR_EXPR)
|| TREE_CODE (TREE_TYPE (to)) == ARRAY_TYPE)
{
enum machine_mode mode1;
to_rtx = expand_normal (tem);
+ /* If the bitfield is volatile, we want to access it in the
+ field's mode, not the computed mode. */
+ if (volatilep
+ && GET_CODE (to_rtx) == MEM
+ && flag_strict_volatile_bitfields > 0)
+ to_rtx = adjust_address (to_rtx, mode1, 0);
+
if (offset != 0)
{
enum machine_mode address_mode;
offset));
}
+ /* No action is needed if the target is not a memory and the field
+ lies completely outside that target. This can occur if the source
+ code contains an out-of-bounds access to a small array. */
+ if (!MEM_P (to_rtx)
+ && GET_MODE (to_rtx) != BLKmode
+ && (unsigned HOST_WIDE_INT) bitpos
+ >= GET_MODE_BITSIZE (GET_MODE (to_rtx)))
+ {
+ expand_normal (from);
+ result = NULL;
+ }
/* Handle expand_expr of a complex value returning a CONCAT. */
- if (GET_CODE (to_rtx) == CONCAT)
+ else if (GET_CODE (to_rtx) == CONCAT)
{
if (COMPLEX_MODE_P (TYPE_MODE (TREE_TYPE (from))))
{
set_mem_attributes (mem, to, 0);
set_mem_addr_space (mem, as);
- icode = movmisalign_optab->handlers[mode].insn_code;
+ icode = optab_handler (movmisalign_optab, mode);
gcc_assert (icode != CODE_FOR_nothing);
op_mode1 = insn_data[icode].operand[1].mode;
/* In case we are returning the contents of an object which overlaps
the place the value is being stored, use a safe function when copying
a value through a pointer into a structure value return block. */
- if (TREE_CODE (to) == RESULT_DECL && TREE_CODE (from) == INDIRECT_REF
+ if (TREE_CODE (to) == RESULT_DECL
+ && TREE_CODE (from) == INDIRECT_REF
&& ADDR_SPACE_GENERIC_P
- (TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (from, 0)))))
+ (TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (from, 0)))))
+ && refs_may_alias_p (to, from)
&& cfun->returns_struct
&& !cfun->returns_pcc_struct)
{
emit_storent_insn (rtx to, rtx from)
{
enum machine_mode mode = GET_MODE (to), imode;
- enum insn_code code = optab_handler (storent_optab, mode)->insn_code;
+ enum insn_code code = optab_handler (storent_optab, mode);
rtx pattern;
if (code == CODE_FOR_nothing)
If CALL_PARAM_P is nonzero, this is a store into a call param on the
stack, and block moves may need to be treated specially.
-
+
If NONTEMPORAL is true, try using a nontemporal store instruction. */
rtx
do_pending_stack_adjust ();
NO_DEFER_POP;
- jumpifnot (TREE_OPERAND (exp, 0), lab1);
+ jumpifnot (TREE_OPERAND (exp, 0), lab1, -1);
store_expr (TREE_OPERAND (exp, 1), target, call_param_p,
nontemporal);
emit_jump_insn (gen_jump (lab2));
BLOCK_OP_NORMAL);
return NULL_RTX;
}
+ else if (TREE_CODE (exp) == MEM_REF
+ && TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) == STRING_CST
+ && integer_zerop (TREE_OPERAND (exp, 1))
+ && !nontemporal && !call_param_p
+ && TYPE_MODE (TREE_TYPE (exp)) == BLKmode)
+ {
+ /* Optimize initialization of an array with a STRING_CST. */
+ HOST_WIDE_INT exp_len, str_copy_len;
+ rtx dest_mem;
+ tree str = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+
+ exp_len = int_expr_size (exp);
+ if (exp_len <= 0)
+ goto normal_expr;
+
+ str_copy_len = strlen (TREE_STRING_POINTER (str));
+ if (str_copy_len < TREE_STRING_LENGTH (str) - 1)
+ goto normal_expr;
+
+ str_copy_len = TREE_STRING_LENGTH (str);
+ if ((STORE_MAX_PIECES & (STORE_MAX_PIECES - 1)) == 0)
+ {
+ str_copy_len += STORE_MAX_PIECES - 1;
+ str_copy_len &= ~(STORE_MAX_PIECES - 1);
+ }
+ str_copy_len = MIN (str_copy_len, exp_len);
+ if (!can_store_by_pieces (str_copy_len, builtin_strncpy_read_str,
+ CONST_CAST(char *, TREE_STRING_POINTER (str)),
+ MEM_ALIGN (target), false))
+ goto normal_expr;
+
+ dest_mem = target;
+
+ dest_mem = store_by_pieces (dest_mem,
+ str_copy_len, builtin_strncpy_read_str,
+ CONST_CAST(char *, TREE_STRING_POINTER (str)),
+ MEM_ALIGN (target), false,
+ exp_len > str_copy_len ? 1 : 0);
+ if (exp_len > str_copy_len)
+ clear_storage (adjust_address (dest_mem, BLKmode, 0),
+ GEN_INT (exp_len - str_copy_len),
+ BLOCK_OP_NORMAL);
+ return NULL_RTX;
+ }
else
{
rtx tmp_target;
FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), idx, purpose, value)
{
- HOST_WIDE_INT mult;
+ HOST_WIDE_INT mult = 1;
- mult = 1;
if (TREE_CODE (purpose) == RANGE_EXPR)
{
tree lo_index = TREE_OPERAND (purpose, 0);
break;
default:
- nz_elts += mult;
- elt_count += mult;
+ {
+ HOST_WIDE_INT tc = count_type_elements (TREE_TYPE (value), true);
+ if (tc < 1)
+ tc = 1;
+ nz_elts += mult * tc;
+ elt_count += mult * tc;
- if (const_from_elts_p && const_p)
- const_p = initializer_constant_valid_p (value, TREE_TYPE (value))
- != NULL_TREE;
+ if (const_from_elts_p && const_p)
+ const_p = initializer_constant_valid_p (value, TREE_TYPE (value))
+ != NULL_TREE;
+ }
break;
}
}
/* Generate a conditional jump to exit the loop. */
exit_cond = build2 (LT_EXPR, integer_type_node,
index, hi_index);
- jumpif (exit_cond, loop_end);
+ jumpif (exit_cond, loop_end, -1);
/* Update the loop counter, and jump to the head of
the loop. */
{
enum machine_mode mode = GET_MODE (target);
- icode = (int) optab_handler (vec_init_optab, mode)->insn_code;
+ icode = (int) optab_handler (vec_init_optab, mode);
if (icode != CODE_FOR_nothing)
{
unsigned int i;
ALIAS_SET is the alias set for the destination. This value will
(in general) be different from that for TARGET, since TARGET is a
reference to the containing structure.
-
+
If NONTEMPORAL is true, try generating a nontemporal store. */
static rtx
operations. */
|| (bitsize >= 0
&& TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) == INTEGER_CST
- && compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) != 0))
+ && compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) != 0)
+ /* If we are expanding a MEM_REF of a non-BLKmode non-addressable
+ decl we must use bitfield operations. */
+ || (bitsize >= 0
+ && TREE_CODE (exp) == MEM_REF
+ && TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
+ && DECL_P (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
+ && !TREE_ADDRESSABLE (TREE_OPERAND (TREE_OPERAND (exp, 0),0 ))
+ && DECL_MODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) != BLKmode))
{
rtx temp;
gimple nop_def;
enum machine_mode mode = VOIDmode;
bool blkmode_bitfield = false;
tree offset = size_zero_node;
- tree bit_offset = bitsize_zero_node;
+ double_int bit_offset = double_int_zero;
/* First get the mode, signedness, and size. We do this from just the
outermost expression. */
+ *pbitsize = -1;
if (TREE_CODE (exp) == COMPONENT_REF)
{
tree field = TREE_OPERAND (exp, 1);
mode = DECL_MODE (field);
else if (DECL_MODE (field) == BLKmode)
blkmode_bitfield = true;
+ else if (TREE_THIS_VOLATILE (exp)
+ && flag_strict_volatile_bitfields > 0)
+ /* Volatile bitfields should be accessed in the mode of the
+ field's type, not the mode computed based on the bit
+ size. */
+ mode = TYPE_MODE (DECL_BIT_FIELD_TYPE (field));
*punsignedp = DECL_UNSIGNED (field);
}
switch (TREE_CODE (exp))
{
case BIT_FIELD_REF:
- bit_offset = size_binop (PLUS_EXPR, bit_offset,
- TREE_OPERAND (exp, 2));
+ bit_offset
+ = double_int_add (bit_offset,
+ tree_to_double_int (TREE_OPERAND (exp, 2)));
break;
case COMPONENT_REF:
break;
offset = size_binop (PLUS_EXPR, offset, this_offset);
- bit_offset = size_binop (PLUS_EXPR, bit_offset,
- DECL_FIELD_BIT_OFFSET (field));
+ bit_offset = double_int_add (bit_offset,
+ tree_to_double_int
+ (DECL_FIELD_BIT_OFFSET (field)));
/* ??? Right now we don't do anything with DECL_OFFSET_ALIGN. */
}
break;
case IMAGPART_EXPR:
- bit_offset = size_binop (PLUS_EXPR, bit_offset,
- bitsize_int (*pbitsize));
+ bit_offset = double_int_add (bit_offset,
+ uhwi_to_double_int (*pbitsize));
break;
case VIEW_CONVERT_EXPR:
goto done;
break;
+ case MEM_REF:
+ /* Hand back the decl for MEM[&decl, off]. */
+ if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR)
+ {
+ tree off = TREE_OPERAND (exp, 1);
+ if (!integer_zerop (off))
+ {
+ double_int boff, coff = mem_ref_offset (exp);
+ boff = double_int_lshift (coff,
+ BITS_PER_UNIT == 8
+ ? 3 : exact_log2 (BITS_PER_UNIT),
+ HOST_BITS_PER_DOUBLE_INT, true);
+ bit_offset = double_int_add (bit_offset, boff);
+ }
+ exp = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+ }
+ goto done;
+
default:
goto done;
}
this conversion. */
if (host_integerp (offset, 0))
{
- double_int tem = double_int_mul (tree_to_double_int (offset),
- uhwi_to_double_int (BITS_PER_UNIT));
- tem = double_int_add (tem, tree_to_double_int (bit_offset));
+ double_int tem = double_int_lshift (tree_to_double_int (offset),
+ BITS_PER_UNIT == 8
+ ? 3 : exact_log2 (BITS_PER_UNIT),
+ HOST_BITS_PER_DOUBLE_INT, true);
+ tem = double_int_add (tem, bit_offset);
if (double_int_fits_in_shwi_p (tem))
{
*pbitpos = double_int_to_shwi (tem);
/* Otherwise, split it up. */
if (offset)
{
- *pbitpos = tree_low_cst (bit_offset, 0);
+ *pbitpos = double_int_to_shwi (bit_offset);
*poffset = offset;
}
case COMPONENT_REF:
{
tree field = TREE_OPERAND (exp, 1);
- packed_p = DECL_PACKED (field)
+ packed_p = DECL_PACKED (field)
|| TYPE_PACKED (TREE_TYPE (field))
|| TYPE_PACKED (TREE_TYPE (exp));
if (packed_p)
break;
case MISALIGNED_INDIRECT_REF:
- case ALIGN_INDIRECT_REF:
case INDIRECT_REF:
if (MEM_P (x)
&& alias_sets_conflict_p (MEM_ALIAS_SET (x),
{
unsigned HOST_WIDE_INT talign = target_align (target) / BITS_PER_UNIT;
unsigned HOST_WIDE_INT factor = highest_pow2_factor (exp);
-
+
return MAX (factor, talign);
}
\f
/* This case will happen via recursion for &a->b. */
return expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
+ case MEM_REF:
+ {
+ tree tem = TREE_OPERAND (exp, 0);
+ if (!integer_zerop (TREE_OPERAND (exp, 1)))
+ tem = build2 (POINTER_PLUS_EXPR, TREE_TYPE (TREE_OPERAND (exp, 1)),
+ tem,
+ double_int_to_tree (sizetype, mem_ref_offset (exp)));
+ return expand_expr (tem, target, tmode, modifier);
+ }
+
case CONST_DECL:
- /* Recurse and make the output_constant_def clause above handle this. */
- return expand_expr_addr_expr_1 (DECL_INITIAL (exp), target,
- tmode, modifier, as);
+ /* Expand the initializer like constants above. */
+ return XEXP (expand_expr_constant (DECL_INITIAL (exp), 0, modifier), 0);
case REALPART_EXPR:
/* The real part of the complex number is always first, therefore
if (modifier != EXPAND_NORMAL)
result = force_operand (result, NULL);
- tmp = expand_expr (offset, NULL_RTX, tmode,
+ tmp = expand_expr (offset, NULL_RTX, tmode,
modifier == EXPAND_INITIALIZER
? EXPAND_INITIALIZER : EXPAND_NORMAL);
if (cfun && EXPR_HAS_LOCATION (exp))
{
location_t saved_location = input_location;
+ location_t saved_curr_loc = get_curr_insn_source_location ();
+ tree saved_block = get_curr_insn_block ();
input_location = EXPR_LOCATION (exp);
set_curr_insn_source_location (input_location);
ret = expand_expr_real_1 (exp, target, tmode, modifier, alt_rtl);
input_location = saved_location;
+ set_curr_insn_block (saved_block);
+ set_curr_insn_source_location (saved_curr_loc);
}
else
{
optab this_optab;
rtx subtarget, original_target;
int ignore;
- tree subexp0, subexp1;
bool reduce_bit_field;
- gimple subexp0_def, subexp1_def;
- tree top0, top1;
location_t loc = ops->location;
tree treeop0, treeop1;
#define REDUCE_BIT_FIELD(expr) (reduce_bit_field \
exactly those that are valid in gimple expressions that aren't
GIMPLE_SINGLE_RHS (or invalid). */
gcc_assert (get_gimple_rhs_class (code) == GIMPLE_UNARY_RHS
- || get_gimple_rhs_class (code) == GIMPLE_BINARY_RHS);
+ || get_gimple_rhs_class (code) == GIMPLE_BINARY_RHS
+ || get_gimple_rhs_class (code) == GIMPLE_TERNARY_RHS);
ignore = (target == const0_rtx
|| ((CONVERT_EXPR_CODE_P (code)
return CONST0_RTX (mode);
}
- case POINTER_PLUS_EXPR:
+ case POINTER_PLUS_EXPR:
/* Even though the sizetype mode and the pointer's mode can be different
- expand is able to handle this correctly and get the correct result out
+ expand is able to handle this correctly and get the correct result out
of the PLUS_EXPR code. */
/* Make sure to sign-extend the sizetype offset in a POINTER_PLUS_EXPR
if sizetype precision is smaller than pointer precision. */
fold_convert_loc (loc, ssizetype,
treeop1));
case PLUS_EXPR:
-
- /* Check if this is a case for multiplication and addition. */
- if ((TREE_CODE (type) == INTEGER_TYPE
- || TREE_CODE (type) == FIXED_POINT_TYPE)
- && (subexp0_def = get_def_for_expr (treeop0,
- MULT_EXPR)))
- {
- tree subsubexp0, subsubexp1;
- gimple subsubexp0_def, subsubexp1_def;
- enum tree_code this_code;
-
- this_code = TREE_CODE (type) == INTEGER_TYPE ? NOP_EXPR
- : FIXED_CONVERT_EXPR;
- subsubexp0 = gimple_assign_rhs1 (subexp0_def);
- subsubexp0_def = get_def_for_expr (subsubexp0, this_code);
- subsubexp1 = gimple_assign_rhs2 (subexp0_def);
- subsubexp1_def = get_def_for_expr (subsubexp1, this_code);
- if (subsubexp0_def && subsubexp1_def
- && (top0 = gimple_assign_rhs1 (subsubexp0_def))
- && (top1 = gimple_assign_rhs1 (subsubexp1_def))
- && (TYPE_PRECISION (TREE_TYPE (top0))
- < TYPE_PRECISION (TREE_TYPE (subsubexp0)))
- && (TYPE_PRECISION (TREE_TYPE (top0))
- == TYPE_PRECISION (TREE_TYPE (top1)))
- && (TYPE_UNSIGNED (TREE_TYPE (top0))
- == TYPE_UNSIGNED (TREE_TYPE (top1))))
- {
- tree op0type = TREE_TYPE (top0);
- enum machine_mode innermode = TYPE_MODE (op0type);
- bool zextend_p = TYPE_UNSIGNED (op0type);
- bool sat_p = TYPE_SATURATING (TREE_TYPE (subsubexp0));
- if (sat_p == 0)
- this_optab = zextend_p ? umadd_widen_optab : smadd_widen_optab;
- else
- this_optab = zextend_p ? usmadd_widen_optab
- : ssmadd_widen_optab;
- if (mode == GET_MODE_2XWIDER_MODE (innermode)
- && (optab_handler (this_optab, mode)->insn_code
- != CODE_FOR_nothing))
- {
- expand_operands (top0, top1, NULL_RTX, &op0, &op1,
- EXPAND_NORMAL);
- op2 = expand_expr (treeop1, subtarget,
- VOIDmode, EXPAND_NORMAL);
- temp = expand_ternary_op (mode, this_optab, op0, op1, op2,
- target, unsignedp);
- gcc_assert (temp);
- return REDUCE_BIT_FIELD (temp);
- }
- }
- }
-
/* If we are adding a constant, a VAR_DECL that is sp, fp, or ap, and
something else, make sure we add the register to the constant and
then to the other thing. This case can occur during strength
return REDUCE_BIT_FIELD (simplify_gen_binary (PLUS, mode, op0, op1));
case MINUS_EXPR:
- /* Check if this is a case for multiplication and subtraction. */
- if ((TREE_CODE (type) == INTEGER_TYPE
- || TREE_CODE (type) == FIXED_POINT_TYPE)
- && (subexp1_def = get_def_for_expr (treeop1,
- MULT_EXPR)))
- {
- tree subsubexp0, subsubexp1;
- gimple subsubexp0_def, subsubexp1_def;
- enum tree_code this_code;
-
- this_code = TREE_CODE (type) == INTEGER_TYPE ? NOP_EXPR
- : FIXED_CONVERT_EXPR;
- subsubexp0 = gimple_assign_rhs1 (subexp1_def);
- subsubexp0_def = get_def_for_expr (subsubexp0, this_code);
- subsubexp1 = gimple_assign_rhs2 (subexp1_def);
- subsubexp1_def = get_def_for_expr (subsubexp1, this_code);
- if (subsubexp0_def && subsubexp1_def
- && (top0 = gimple_assign_rhs1 (subsubexp0_def))
- && (top1 = gimple_assign_rhs1 (subsubexp1_def))
- && (TYPE_PRECISION (TREE_TYPE (top0))
- < TYPE_PRECISION (TREE_TYPE (subsubexp0)))
- && (TYPE_PRECISION (TREE_TYPE (top0))
- == TYPE_PRECISION (TREE_TYPE (top1)))
- && (TYPE_UNSIGNED (TREE_TYPE (top0))
- == TYPE_UNSIGNED (TREE_TYPE (top1))))
- {
- tree op0type = TREE_TYPE (top0);
- enum machine_mode innermode = TYPE_MODE (op0type);
- bool zextend_p = TYPE_UNSIGNED (op0type);
- bool sat_p = TYPE_SATURATING (TREE_TYPE (subsubexp0));
- if (sat_p == 0)
- this_optab = zextend_p ? umsub_widen_optab : smsub_widen_optab;
- else
- this_optab = zextend_p ? usmsub_widen_optab
- : ssmsub_widen_optab;
- if (mode == GET_MODE_2XWIDER_MODE (innermode)
- && (optab_handler (this_optab, mode)->insn_code
- != CODE_FOR_nothing))
- {
- expand_operands (top0, top1, NULL_RTX, &op0, &op1,
- EXPAND_NORMAL);
- op2 = expand_expr (treeop0, subtarget,
- VOIDmode, EXPAND_NORMAL);
- temp = expand_ternary_op (mode, this_optab, op0, op1, op2,
- target, unsignedp);
- gcc_assert (temp);
- return REDUCE_BIT_FIELD (temp);
- }
- }
- }
-
/* For initializers, we are allowed to return a MINUS of two
symbolic constants. Here we handle all cases when both operands
are constant. */
goto binop2;
- case MULT_EXPR:
- /* If this is a fixed-point operation, then we cannot use the code
- below because "expand_mult" doesn't support sat/no-sat fixed-point
- multiplications. */
- if (ALL_FIXED_POINT_MODE_P (mode))
- goto binop;
+ case WIDEN_MULT_PLUS_EXPR:
+ case WIDEN_MULT_MINUS_EXPR:
+ expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+ op2 = expand_normal (ops->op2);
+ target = expand_widen_pattern_expr (ops, op0, op1, op2,
+ target, unsignedp);
+ return target;
+ case WIDEN_MULT_EXPR:
/* If first operand is constant, swap them.
Thus the following special case checks need only
check the second operand. */
treeop1 = t1;
}
- /* Attempt to return something suitable for generating an
- indexed address, for machines that support that. */
-
- if (modifier == EXPAND_SUM && mode == ptr_mode
- && host_integerp (treeop1, 0))
- {
- tree exp1 = treeop1;
-
- op0 = expand_expr (treeop0, subtarget, VOIDmode,
- EXPAND_SUM);
-
- if (!REG_P (op0))
- op0 = force_operand (op0, NULL_RTX);
- if (!REG_P (op0))
- op0 = copy_to_mode_reg (mode, op0);
-
- return REDUCE_BIT_FIELD (gen_rtx_MULT (mode, op0,
- gen_int_mode (tree_low_cst (exp1, 0),
- TYPE_MODE (TREE_TYPE (exp1)))));
- }
-
- if (modifier == EXPAND_STACK_PARM)
- target = 0;
-
- /* Check for multiplying things that have been extended
- from a narrower type. If this machine supports multiplying
- in that narrower type with a result in the desired type,
- do it that way, and avoid the explicit type-conversion. */
-
- subexp0 = treeop0;
- subexp1 = treeop1;
- subexp0_def = get_def_for_expr (subexp0, NOP_EXPR);
- subexp1_def = get_def_for_expr (subexp1, NOP_EXPR);
- top0 = top1 = NULL_TREE;
-
/* First, check if we have a multiplication of one signed and one
unsigned operand. */
- if (subexp0_def
- && (top0 = gimple_assign_rhs1 (subexp0_def))
- && subexp1_def
- && (top1 = gimple_assign_rhs1 (subexp1_def))
- && TREE_CODE (type) == INTEGER_TYPE
- && (TYPE_PRECISION (TREE_TYPE (top0))
- < TYPE_PRECISION (TREE_TYPE (subexp0)))
- && (TYPE_PRECISION (TREE_TYPE (top0))
- == TYPE_PRECISION (TREE_TYPE (top1)))
- && (TYPE_UNSIGNED (TREE_TYPE (top0))
- != TYPE_UNSIGNED (TREE_TYPE (top1))))
+ if (TREE_CODE (treeop1) != INTEGER_CST
+ && (TYPE_UNSIGNED (TREE_TYPE (treeop0))
+ != TYPE_UNSIGNED (TREE_TYPE (treeop1))))
{
- enum machine_mode innermode
- = TYPE_MODE (TREE_TYPE (top0));
+ enum machine_mode innermode = TYPE_MODE (TREE_TYPE (treeop0));
this_optab = usmul_widen_optab;
- if (mode == GET_MODE_WIDER_MODE (innermode))
+ if (mode == GET_MODE_2XWIDER_MODE (innermode))
{
- if (optab_handler (this_optab, mode)->insn_code != CODE_FOR_nothing)
+ if (optab_handler (this_optab, mode) != CODE_FOR_nothing)
{
- if (TYPE_UNSIGNED (TREE_TYPE (top0)))
- expand_operands (top0, top1, NULL_RTX, &op0, &op1,
+ if (TYPE_UNSIGNED (TREE_TYPE (treeop0)))
+ expand_operands (treeop0, treeop1, subtarget, &op0, &op1,
EXPAND_NORMAL);
else
- expand_operands (top0, top1, NULL_RTX, &op1, &op0,
+ expand_operands (treeop0, treeop1, subtarget, &op1, &op0,
EXPAND_NORMAL);
-
goto binop3;
}
}
}
- /* Check for a multiplication with matching signedness. If
- valid, TOP0 and TOP1 were set in the previous if
- condition. */
- else if (top0
- && TREE_CODE (type) == INTEGER_TYPE
- && (TYPE_PRECISION (TREE_TYPE (top0))
- < TYPE_PRECISION (TREE_TYPE (subexp0)))
- && ((TREE_CODE (subexp1) == INTEGER_CST
- && int_fits_type_p (subexp1, TREE_TYPE (top0))
- /* Don't use a widening multiply if a shift will do. */
- && ((GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (subexp1)))
- > HOST_BITS_PER_WIDE_INT)
- || exact_log2 (TREE_INT_CST_LOW (subexp1)) < 0))
- ||
- (top1
- && (TYPE_PRECISION (TREE_TYPE (top1))
- == TYPE_PRECISION (TREE_TYPE (top0))
- /* If both operands are extended, they must either both
- be zero-extended or both be sign-extended. */
- && (TYPE_UNSIGNED (TREE_TYPE (top1))
- == TYPE_UNSIGNED (TREE_TYPE (top0)))))))
+ /* Check for a multiplication with matching signedness. */
+ else if ((TREE_CODE (treeop1) == INTEGER_CST
+ && int_fits_type_p (treeop1, TREE_TYPE (treeop0)))
+ || (TYPE_UNSIGNED (TREE_TYPE (treeop1))
+ == TYPE_UNSIGNED (TREE_TYPE (treeop0))))
{
- tree op0type = TREE_TYPE (top0);
+ tree op0type = TREE_TYPE (treeop0);
enum machine_mode innermode = TYPE_MODE (op0type);
bool zextend_p = TYPE_UNSIGNED (op0type);
optab other_optab = zextend_p ? smul_widen_optab : umul_widen_optab;
if (mode == GET_MODE_2XWIDER_MODE (innermode))
{
- if (optab_handler (this_optab, mode)->insn_code != CODE_FOR_nothing)
+ if (optab_handler (this_optab, mode) != CODE_FOR_nothing)
{
- if (TREE_CODE (subexp1) == INTEGER_CST)
- expand_operands (top0, subexp1, NULL_RTX, &op0, &op1,
- EXPAND_NORMAL);
- else
- expand_operands (top0, top1, NULL_RTX, &op0, &op1,
- EXPAND_NORMAL);
- goto binop3;
+ expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1,
+ EXPAND_NORMAL);
+ temp = expand_widening_mult (mode, op0, op1, target,
+ unsignedp, this_optab);
+ return REDUCE_BIT_FIELD (temp);
}
- else if (optab_handler (other_optab, mode)->insn_code != CODE_FOR_nothing
- && innermode == word_mode)
+ if (optab_handler (other_optab, mode) != CODE_FOR_nothing
+ && innermode == word_mode)
{
rtx htem, hipart;
- op0 = expand_normal (top0);
- if (TREE_CODE (subexp1) == INTEGER_CST)
+ op0 = expand_normal (treeop0);
+ if (TREE_CODE (treeop1) == INTEGER_CST)
op1 = convert_modes (innermode, mode,
- expand_normal (subexp1), unsignedp);
+ expand_normal (treeop1), unsignedp);
else
- op1 = expand_normal (top1);
+ op1 = expand_normal (treeop1);
temp = expand_binop (mode, other_optab, op0, op1, target,
unsignedp, OPTAB_LIB_WIDEN);
hipart = gen_highpart (innermode, temp);
}
}
}
- expand_operands (subexp0, subexp1, subtarget, &op0, &op1, EXPAND_NORMAL);
+ treeop0 = fold_build1 (CONVERT_EXPR, type, treeop0);
+ treeop1 = fold_build1 (CONVERT_EXPR, type, treeop1);
+ expand_operands (treeop0, treeop1, subtarget, &op0, &op1, EXPAND_NORMAL);
+ return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1, target, unsignedp));
+
+ case MULT_EXPR:
+ /* If this is a fixed-point operation, then we cannot use the code
+ below because "expand_mult" doesn't support sat/no-sat fixed-point
+ multiplications. */
+ if (ALL_FIXED_POINT_MODE_P (mode))
+ goto binop;
+
+ /* If first operand is constant, swap them.
+ Thus the following special case checks need only
+ check the second operand. */
+ if (TREE_CODE (treeop0) == INTEGER_CST)
+ {
+ tree t1 = treeop0;
+ treeop0 = treeop1;
+ treeop1 = t1;
+ }
+
+ /* Attempt to return something suitable for generating an
+ indexed address, for machines that support that. */
+
+ if (modifier == EXPAND_SUM && mode == ptr_mode
+ && host_integerp (treeop1, 0))
+ {
+ tree exp1 = treeop1;
+
+ op0 = expand_expr (treeop0, subtarget, VOIDmode,
+ EXPAND_SUM);
+
+ if (!REG_P (op0))
+ op0 = force_operand (op0, NULL_RTX);
+ if (!REG_P (op0))
+ op0 = copy_to_mode_reg (mode, op0);
+
+ return REDUCE_BIT_FIELD (gen_rtx_MULT (mode, op0,
+ gen_int_mode (tree_low_cst (exp1, 0),
+ TYPE_MODE (TREE_TYPE (exp1)))));
+ }
+
+ if (modifier == EXPAND_STACK_PARM)
+ target = 0;
+
+ expand_operands (treeop0, treeop1, subtarget, &op0, &op1, EXPAND_NORMAL);
return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1, target, unsignedp));
case TRUNC_DIV_EXPR:
temp = gen_label_rtx ();
do_compare_rtx_and_jump (target, cmpop1, comparison_code,
- unsignedp, mode, NULL_RTX, NULL_RTX, temp);
+ unsignedp, mode, NULL_RTX, NULL_RTX, temp,
+ -1);
}
emit_move_insn (target, op1);
emit_label (temp);
emit_move_insn (target, const0_rtx);
op1 = gen_label_rtx ();
- jumpifnot_1 (code, treeop0, treeop1, op1);
+ jumpifnot_1 (code, treeop0, treeop1, op1, -1);
emit_move_insn (target, const1_rtx);
location_t loc = EXPR_LOCATION (exp);
struct separate_ops ops;
tree treeop0, treeop1, treeop2;
+ tree ssa_name = NULL_TREE;
+ gimple g;
type = TREE_TYPE (exp);
mode = TYPE_MODE (type);
base variable. This unnecessarily allocates a pseudo, see how we can
reuse it, if partition base vars have it set already. */
if (!currently_expanding_to_rtl)
- return expand_expr_real_1 (SSA_NAME_VAR (exp), target, tmode, modifier, NULL);
- {
- gimple g = get_gimple_for_ssa_name (exp);
- if (g)
- return expand_expr_real_1 (gimple_assign_rhs_to_tree (g), target,
- tmode, modifier, NULL);
- }
- decl_rtl = get_rtx_for_ssa_name (exp);
- exp = SSA_NAME_VAR (exp);
+ return expand_expr_real_1 (SSA_NAME_VAR (exp), target, tmode, modifier,
+ NULL);
+
+ g = get_gimple_for_ssa_name (exp);
+ if (g)
+ return expand_expr_real (gimple_assign_rhs_to_tree (g), target, tmode,
+ modifier, NULL);
+
+ ssa_name = exp;
+ decl_rtl = get_rtx_for_ssa_name (ssa_name);
+ exp = SSA_NAME_VAR (ssa_name);
goto expand_decl_rtl;
case PARM_DECL:
expand_decl_rtl:
gcc_assert (decl_rtl);
decl_rtl = copy_rtx (decl_rtl);
+ /* Record writes to register variables. */
+ if (modifier == EXPAND_WRITE && REG_P (decl_rtl)
+ && REGNO (decl_rtl) < FIRST_PSEUDO_REGISTER)
+ {
+ int i = REGNO (decl_rtl);
+ int nregs = hard_regno_nregs[i][GET_MODE (decl_rtl)];
+ while (nregs)
+ {
+ SET_HARD_REG_BIT (crtl->asm_clobbers, i);
+ i++;
+ nregs--;
+ }
+ }
/* Ensure variable marked as used even if it doesn't go through
a parser. If it hasn't be used yet, write out an external
/* If the mode of DECL_RTL does not match that of the decl, it
must be a promoted value. We return a SUBREG of the wanted mode,
but mark it so that we know that it was already extended. */
-
- if (REG_P (decl_rtl)
- && GET_MODE (decl_rtl) != DECL_MODE (exp))
+ if (REG_P (decl_rtl) && GET_MODE (decl_rtl) != DECL_MODE (exp))
{
enum machine_mode pmode;
- /* Get the signedness used for this variable. Ensure we get the
- same mode we got when the variable was declared. */
- pmode = promote_decl_mode (exp, &unsignedp);
+ /* Get the signedness to be used for this variable. Ensure we get
+ the same mode we got when the variable was declared. */
+ if (code == SSA_NAME
+ && (g = SSA_NAME_DEF_STMT (ssa_name))
+ && gimple_code (g) == GIMPLE_CALL)
+ pmode = promote_function_mode (type, mode, &unsignedp,
+ TREE_TYPE
+ (TREE_TYPE (gimple_call_fn (g))),
+ 2);
+ else
+ pmode = promote_decl_mode (exp, &unsignedp);
gcc_assert (GET_MODE (decl_rtl) == pmode);
temp = gen_lowpart_SUBREG (mode, decl_rtl);
return expand_constructor (exp, target, modifier, false);
case MISALIGNED_INDIRECT_REF:
- case ALIGN_INDIRECT_REF:
case INDIRECT_REF:
{
tree exp1 = treeop0;
addr_space_t as = ADDR_SPACE_GENERIC;
- enum machine_mode address_mode = Pmode;
if (modifier != EXPAND_WRITE)
{
}
if (POINTER_TYPE_P (TREE_TYPE (exp1)))
- {
- as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp1)));
- address_mode = targetm.addr_space.address_mode (as);
- }
+ as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp1)));
op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM);
op0 = memory_address_addr_space (mode, op0, as);
- if (code == ALIGN_INDIRECT_REF)
- {
- int align = TYPE_ALIGN_UNIT (type);
- op0 = gen_rtx_AND (address_mode, op0, GEN_INT (-align));
- op0 = memory_address_addr_space (mode, op0, as);
- }
-
temp = gen_rtx_MEM (mode, op0);
set_mem_attributes (temp, exp, 0);
|| modifier == EXPAND_STACK_PARM);
/* The vectorizer should have already checked the mode. */
- icode = optab_handler (movmisalign_optab, mode)->insn_code;
+ icode = optab_handler (movmisalign_optab, mode);
gcc_assert (icode != CODE_FOR_nothing);
/* We've already validated the memory, and we're creating a
{
addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (exp));
struct mem_address addr;
+ tree base;
get_address_description (exp, &addr);
op0 = addr_for_mem_ref (&addr, as, true);
temp = gen_rtx_MEM (mode, op0);
set_mem_attributes (temp, TMR_ORIGINAL (exp), 0);
set_mem_addr_space (temp, as);
+ base = get_base_address (TMR_ORIGINAL (exp));
+ if (INDIRECT_REF_P (base)
+ && TMR_BASE (exp)
+ && TREE_CODE (TMR_BASE (exp)) == SSA_NAME
+ && POINTER_TYPE_P (TREE_TYPE (TMR_BASE (exp))))
+ {
+ set_mem_expr (temp, build1 (INDIRECT_REF,
+ TREE_TYPE (exp), TMR_BASE (exp)));
+ set_mem_offset (temp, NULL_RTX);
+ }
}
return temp;
+ case MEM_REF:
+ {
+ addr_space_t as
+ = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1))));
+ enum machine_mode address_mode;
+ tree base = TREE_OPERAND (exp, 0);
+ gimple def_stmt;
+ /* Handle expansion of non-aliased memory with non-BLKmode. That
+ might end up in a register. */
+ if (TREE_CODE (base) == ADDR_EXPR)
+ {
+ HOST_WIDE_INT offset = mem_ref_offset (exp).low;
+ tree bit_offset;
+ base = TREE_OPERAND (base, 0);
+ if (!DECL_P (base))
+ {
+ HOST_WIDE_INT off;
+ base = get_addr_base_and_unit_offset (base, &off);
+ gcc_assert (base);
+ offset += off;
+ }
+ /* If we are expanding a MEM_REF of a non-BLKmode non-addressable
+ decl we must use bitfield operations. */
+ if (DECL_P (base)
+ && !TREE_ADDRESSABLE (base)
+ && DECL_MODE (base) != BLKmode
+ && DECL_RTL_SET_P (base)
+ && !MEM_P (DECL_RTL (base)))
+ {
+ tree bftype;
+ if (offset == 0
+ && host_integerp (TYPE_SIZE (TREE_TYPE (exp)), 1)
+ && (GET_MODE_BITSIZE (DECL_MODE (base))
+ == TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (exp)))))
+ return expand_expr (build1 (VIEW_CONVERT_EXPR,
+ TREE_TYPE (exp), base),
+ target, tmode, modifier);
+ bit_offset = bitsize_int (offset * BITS_PER_UNIT);
+ bftype = TREE_TYPE (base);
+ if (TYPE_MODE (TREE_TYPE (exp)) != BLKmode)
+ bftype = TREE_TYPE (exp);
+ return expand_expr (build3 (BIT_FIELD_REF, bftype,
+ base,
+ TYPE_SIZE (TREE_TYPE (exp)),
+ bit_offset),
+ target, tmode, modifier);
+ }
+ }
+ address_mode = targetm.addr_space.address_mode (as);
+ base = TREE_OPERAND (exp, 0);
+ if ((def_stmt = get_def_for_expr (base, BIT_AND_EXPR)))
+ base = build2 (BIT_AND_EXPR, TREE_TYPE (base),
+ gimple_assign_rhs1 (def_stmt),
+ gimple_assign_rhs2 (def_stmt));
+ if (!integer_zerop (TREE_OPERAND (exp, 1)))
+ base = build2 (POINTER_PLUS_EXPR, TREE_TYPE (base),
+ base, double_int_to_tree (sizetype,
+ mem_ref_offset (exp)));
+ op0 = expand_expr (base, NULL_RTX, address_mode, EXPAND_SUM);
+ op0 = memory_address_addr_space (mode, op0, as);
+ temp = gen_rtx_MEM (mode, op0);
+ set_mem_attributes (temp, exp, 0);
+ set_mem_addr_space (temp, as);
+ if (TREE_THIS_VOLATILE (exp))
+ MEM_VOLATILE_P (temp) = 1;
+ return temp;
+ }
+
case ARRAY_REF:
{
|| modifier == EXPAND_STACK_PARM)
? modifier : EXPAND_NORMAL);
+
+ /* If the bitfield is volatile, we want to access it in the
+ field's mode, not the computed mode. */
+ if (volatilep
+ && GET_CODE (op0) == MEM
+ && flag_strict_volatile_bitfields > 0)
+ op0 = adjust_address (op0, mode1, 0);
+
mode2
= CONSTANT_P (op0) ? TYPE_MODE (TREE_TYPE (tem)) : GET_MODE (op0);
&& GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT
&& modifier != EXPAND_CONST_ADDRESS
&& modifier != EXPAND_INITIALIZER)
+ /* If the field is volatile, we always want an aligned
+ access. */
+ || (volatilep && flag_strict_volatile_bitfields > 0)
/* If the field isn't aligned enough to fetch as a memref,
fetch it as a bit field. */
|| (mode1 != BLKmode
op0 = force_reg (GET_MODE (op0), op0);
op0 = gen_lowpart (mode, 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 (mode))
- op0 = convert_modes (mode, GET_MODE (op0), op0,
+ /* If both types are integral, convert from one mode to the other. */
+ else if (INTEGRAL_TYPE_P (type) && INTEGRAL_TYPE_P (TREE_TYPE (treeop0)))
+ op0 = convert_modes (mode, GET_MODE (op0), op0,
TYPE_UNSIGNED (TREE_TYPE (treeop0)));
/* As a last resort, spill op0 to memory, and reload it in a
different mode. */
emit_move_insn (target, const0_rtx);
op1 = gen_label_rtx ();
- jumpifnot_1 (code, treeop0, treeop1, op1);
+ jumpifnot_1 (code, treeop0, treeop1, op1, -1);
if (target)
emit_move_insn (target, const1_rtx);
NO_DEFER_POP;
op0 = gen_label_rtx ();
op1 = gen_label_rtx ();
- jumpifnot (treeop0, op0);
+ jumpifnot (treeop0, op0, -1);
store_expr (treeop1, temp,
modifier == EXPAND_STACK_PARM,
false);
int value = TREE_CODE (rhs) == BIT_IOR_EXPR;
do_jump (TREE_OPERAND (rhs, 1),
value ? label : 0,
- value ? 0 : label);
+ value ? 0 : label, -1);
expand_assignment (lhs, build_int_cst (TREE_TYPE (rhs), value),
MOVE_NONTEMPORAL (exp));
do_pending_stack_adjust ();
}
else if (TYPE_UNSIGNED (type))
{
- rtx mask;
- if (prec < HOST_BITS_PER_WIDE_INT)
- mask = immed_double_const (((unsigned HOST_WIDE_INT) 1 << prec) - 1, 0,
- GET_MODE (exp));
- else
- mask = immed_double_const ((unsigned HOST_WIDE_INT) -1,
- ((unsigned HOST_WIDE_INT) 1
- << (prec - HOST_BITS_PER_WIDE_INT)) - 1,
- GET_MODE (exp));
+ rtx mask = immed_double_int_const (double_int_mask (prec),
+ GET_MODE (exp));
return expand_and (GET_MODE (exp), exp, mask, target);
}
else
return 1;
}
-/* Nonzero if the mode is a valid vector mode for this architecture.
- This returns nonzero even if there is no hardware support for the
- vector mode, but we can emulate with narrower modes. */
-
-int
-vector_mode_valid_p (enum machine_mode mode)
-{
- enum mode_class mclass = GET_MODE_CLASS (mode);
- enum machine_mode innermode;
-
- /* Doh! What's going on? */
- if (mclass != MODE_VECTOR_INT
- && mclass != MODE_VECTOR_FLOAT
- && mclass != MODE_VECTOR_FRACT
- && mclass != MODE_VECTOR_UFRACT
- && mclass != MODE_VECTOR_ACCUM
- && mclass != MODE_VECTOR_UACCUM)
- return 0;
-
- /* Hardware support. Woo hoo! */
- if (targetm.vector_mode_supported_p (mode))
- return 1;
-
- innermode = GET_MODE_INNER (mode);
-
- /* We should probably return 1 if requesting V4DI and we have no DI,
- but we have V2DI, but this is probably very unlikely. */
-
- /* If we have support for the inner mode, we can safely emulate it.
- We may not have V2DI, but me can emulate with a pair of DIs. */
- return targetm.scalar_mode_supported_p (innermode);
-}
-
/* Return a CONST_VECTOR rtx for a VECTOR_CST tree. */
static rtx
const_vector_from_tree (tree exp)
RTVEC_ELT (v, i) = CONST_FIXED_FROM_FIXED_VALUE (TREE_FIXED_CST (elt),
inner);
else
- RTVEC_ELT (v, i) = immed_double_const (TREE_INT_CST_LOW (elt),
- TREE_INT_CST_HIGH (elt),
- inner);
+ RTVEC_ELT (v, i) = immed_double_int_const (tree_to_double_int (elt),
+ inner);
}
/* Initialize remaining elements to 0. */