/* 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, 2010, 2011
- Free Software Foundation, Inc.
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
+ 2012 Free Software Foundation, Inc.
This file is part of GCC.
int reverse;
};
-static unsigned HOST_WIDE_INT move_by_pieces_ninsns (unsigned HOST_WIDE_INT,
- unsigned int,
- unsigned int);
static void move_by_pieces_1 (rtx (*) (rtx, ...), enum machine_mode,
struct move_by_pieces_d *);
static bool block_move_libcall_safe_for_call_parm (void);
rtx new_from;
enum machine_mode full_mode
= smallest_mode_for_size (GET_MODE_BITSIZE (from_mode), MODE_INT);
+ convert_optab ctab = unsignedp ? zext_optab : sext_optab;
+ enum insn_code icode;
- gcc_assert (convert_optab_handler (sext_optab, full_mode, from_mode)
- != CODE_FOR_nothing);
+ icode = convert_optab_handler (ctab, full_mode, from_mode);
+ gcc_assert (icode != CODE_FOR_nothing);
if (to_mode == full_mode)
{
- emit_unop_insn (convert_optab_handler (sext_optab, full_mode,
- from_mode),
- to, from, UNKNOWN);
+ emit_unop_insn (icode, to, from, UNKNOWN);
return;
}
new_from = gen_reg_rtx (full_mode);
- emit_unop_insn (convert_optab_handler (sext_optab, full_mode, from_mode),
- new_from, from, UNKNOWN);
+ emit_unop_insn (icode, new_from, from, UNKNOWN);
/* else proceed to integer conversions below. */
from_mode = full_mode;
unsigned int align, int endp)
{
struct move_by_pieces_d data;
- enum machine_mode to_addr_mode, from_addr_mode
- = targetm.addr_space.address_mode (MEM_ADDR_SPACE (from));
+ enum machine_mode to_addr_mode;
+ enum machine_mode from_addr_mode = get_address_mode (from);
rtx to_addr, from_addr = XEXP (from, 0);
unsigned int max_size = MOVE_MAX_PIECES + 1;
enum insn_code icode;
data.from_addr = from_addr;
if (to)
{
- to_addr_mode = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to));
+ to_addr_mode = get_address_mode (to);
to_addr = XEXP (to, 0);
data.to = to;
data.autinc_to
if (USE_LOAD_PRE_DECREMENT (mode) && data.reverse && ! data.autinc_from)
{
data.from_addr = copy_to_mode_reg (from_addr_mode,
- plus_constant (from_addr, len));
+ plus_constant (from_addr_mode,
+ from_addr, len));
data.autinc_from = 1;
data.explicit_inc_from = -1;
}
if (USE_STORE_PRE_DECREMENT (mode) && data.reverse && ! data.autinc_to)
{
data.to_addr = copy_to_mode_reg (to_addr_mode,
- plus_constant (to_addr, len));
+ plus_constant (to_addr_mode,
+ to_addr, len));
data.autinc_to = 1;
data.explicit_inc_to = -1;
}
emit_insn (gen_add2_insn (data.to_addr, constm1_rtx));
else
data.to_addr = copy_to_mode_reg (to_addr_mode,
- plus_constant (data.to_addr,
+ plus_constant (to_addr_mode,
+ data.to_addr,
-1));
}
to1 = adjust_automodify_address (data.to, QImode, data.to_addr,
/* Return number of insns required to move L bytes by pieces.
ALIGN (in bits) is maximum alignment we can assume. */
-static unsigned HOST_WIDE_INT
+unsigned HOST_WIDE_INT
move_by_pieces_ninsns (unsigned HOST_WIDE_INT l, unsigned int align,
unsigned int max_size)
{
pseudos. We can then place those new pseudos into a VAR_DECL and
use them later. */
- dst_addr = copy_to_mode_reg (Pmode, XEXP (dst, 0));
- src_addr = copy_to_mode_reg (Pmode, XEXP (src, 0));
+ dst_addr = copy_addr_to_reg (XEXP (dst, 0));
+ src_addr = copy_addr_to_reg (XEXP (src, 0));
dst_addr = convert_memory_address (ptr_mode, dst_addr);
src_addr = convert_memory_address (ptr_mode, src_addr);
}
/* A subroutine of emit_block_move_via_libcall. Create the tree node
- for the function we use for block copies. The first time FOR_CALL
- is true, we call assemble_external. */
+ for the function we use for block copies. */
static GTY(()) tree block_move_fn;
{
if (!block_move_fn)
{
- tree args, fn;
+ tree args, fn, attrs, attr_args;
fn = get_identifier ("memcpy");
args = build_function_type_list (ptr_type_node, ptr_type_node,
DECL_VISIBILITY (fn) = VISIBILITY_DEFAULT;
DECL_VISIBILITY_SPECIFIED (fn) = 1;
+ attr_args = build_tree_list (NULL_TREE, build_string (1, "1"));
+ attrs = tree_cons (get_identifier ("fn spec"), attr_args, NULL);
+
+ decl_attributes (&fn, attrs, ATTR_FLAG_BUILT_IN);
+
block_move_fn = fn;
}
{
emitted_extern = true;
make_decl_rtl (block_move_fn);
- assemble_external (block_move_fn);
}
return block_move_fn;
unsigned int align ATTRIBUTE_UNUSED)
{
rtx cmp_label, top_label, iter, x_addr, y_addr, tmp;
- enum machine_mode x_addr_mode
- = targetm.addr_space.address_mode (MEM_ADDR_SPACE (x));
- enum machine_mode y_addr_mode
- = targetm.addr_space.address_mode (MEM_ADDR_SPACE (y));
+ enum machine_mode x_addr_mode = get_address_mode (x);
+ enum machine_mode y_addr_mode = get_address_mode (y);
enum machine_mode iter_mode;
iter_mode = GET_MODE (size);
{
enum machine_mode imode = int_mode_for_mode (GET_MODE (orig_src));
if (imode == BLKmode)
- src = assign_stack_temp (GET_MODE (orig_src), ssize, 0);
+ src = assign_stack_temp (GET_MODE (orig_src), ssize);
else
src = gen_reg_rtx (imode);
if (imode != BLKmode)
rtx mem;
gcc_assert (!bytepos);
- mem = assign_stack_temp (GET_MODE (src), slen, 0);
+ mem = assign_stack_temp (GET_MODE (src), slen);
emit_move_insn (mem, src);
tmps[i] = extract_bit_field (mem, bytelen * BITS_PER_UNIT,
0, 1, false, NULL_RTX, mode, mode);
int slen = GET_MODE_SIZE (GET_MODE (src));
rtx mem;
- mem = assign_stack_temp (GET_MODE (src), slen, 0);
+ mem = assign_stack_temp (GET_MODE (src), slen);
emit_move_insn (mem, src);
tmps[i] = adjust_address (mem, mode, (int) bytepos);
}
{
enum machine_mode imode = int_mode_for_mode (GET_MODE (orig_dst));
if (imode == BLKmode)
- dst = assign_stack_temp (GET_MODE (orig_dst), ssize, 0);
+ dst = assign_stack_temp (GET_MODE (orig_dst), ssize);
else
dst = gen_reg_rtx (imode);
emit_group_store (dst, src, type, ssize);
it. Allocate a temporary, and split this into a store/load to/from
the temporary. */
- temp = assign_stack_temp (GET_MODE (dst), ssize, 0);
+ temp = assign_stack_temp (GET_MODE (dst), ssize);
emit_group_store (temp, src, type, ssize);
emit_group_load (dst, temp, type, ssize);
return;
>= GET_MODE_ALIGNMENT (tmp_mode))
{
dest = assign_stack_temp (dest_mode,
- GET_MODE_SIZE (dest_mode),
- 0);
+ GET_MODE_SIZE (dest_mode));
emit_move_insn (adjust_address (dest,
tmp_mode,
bytepos),
else
{
dest = assign_stack_temp (tmp_mode,
- GET_MODE_SIZE (tmp_mode),
- 0);
+ GET_MODE_SIZE (tmp_mode));
emit_move_insn (dest, tmps[i]);
dst = adjust_address (dest, dest_mode, bytepos);
}
tgtblk = assign_temp (build_qualified_type (type,
(TYPE_QUALS (type)
| TYPE_QUAL_CONST)),
- 0, 1, 1);
+ 1, 1);
preserve_temp_slots (tgtblk);
}
return tgtblk;
}
+/* Copy BLKmode value SRC into a register of mode MODE. Return the
+ register if it contains any data, otherwise return null.
+
+ This is used on targets that return BLKmode values in registers. */
+
+rtx
+copy_blkmode_to_reg (enum machine_mode mode, tree src)
+{
+ int i, n_regs;
+ unsigned HOST_WIDE_INT bitpos, xbitpos, padding_correction = 0, bytes;
+ unsigned int bitsize;
+ rtx *dst_words, dst, x, src_word = NULL_RTX, dst_word = NULL_RTX;
+ enum machine_mode dst_mode;
+
+ gcc_assert (TYPE_MODE (TREE_TYPE (src)) == BLKmode);
+
+ x = expand_normal (src);
+
+ bytes = int_size_in_bytes (TREE_TYPE (src));
+ if (bytes == 0)
+ return NULL_RTX;
+
+ /* If the structure doesn't take up a whole number of words, see
+ whether the register value should be padded on the left or on
+ the right. Set PADDING_CORRECTION to the number of padding
+ bits needed on the left side.
+
+ In most ABIs, the structure will be returned at the least end of
+ the register, which translates to right padding on little-endian
+ targets and left padding on big-endian targets. The opposite
+ holds if the structure is returned at the most significant
+ end of the register. */
+ if (bytes % UNITS_PER_WORD != 0
+ && (targetm.calls.return_in_msb (TREE_TYPE (src))
+ ? !BYTES_BIG_ENDIAN
+ : BYTES_BIG_ENDIAN))
+ padding_correction = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD)
+ * BITS_PER_UNIT));
+
+ n_regs = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+ dst_words = XALLOCAVEC (rtx, n_regs);
+ bitsize = MIN (TYPE_ALIGN (TREE_TYPE (src)), BITS_PER_WORD);
+
+ /* Copy the structure BITSIZE bits at a time. */
+ for (bitpos = 0, xbitpos = padding_correction;
+ bitpos < bytes * BITS_PER_UNIT;
+ bitpos += bitsize, xbitpos += bitsize)
+ {
+ /* We need a new destination pseudo each time xbitpos is
+ on a word boundary and when xbitpos == padding_correction
+ (the first time through). */
+ if (xbitpos % BITS_PER_WORD == 0
+ || xbitpos == padding_correction)
+ {
+ /* Generate an appropriate register. */
+ dst_word = gen_reg_rtx (word_mode);
+ dst_words[xbitpos / BITS_PER_WORD] = dst_word;
+
+ /* Clear the destination before we move anything into it. */
+ emit_move_insn (dst_word, CONST0_RTX (word_mode));
+ }
+
+ /* We need a new source operand each time bitpos is on a word
+ boundary. */
+ if (bitpos % BITS_PER_WORD == 0)
+ src_word = operand_subword_force (x, bitpos / BITS_PER_WORD, BLKmode);
+
+ /* Use bitpos for the source extraction (left justified) and
+ xbitpos for the destination store (right justified). */
+ store_bit_field (dst_word, bitsize, xbitpos % BITS_PER_WORD,
+ 0, 0, word_mode,
+ extract_bit_field (src_word, bitsize,
+ bitpos % BITS_PER_WORD, 1, false,
+ NULL_RTX, word_mode, word_mode));
+ }
+
+ if (mode == BLKmode)
+ {
+ /* Find the smallest integer mode large enough to hold the
+ entire structure. */
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+ mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
+ /* Have we found a large enough mode? */
+ if (GET_MODE_SIZE (mode) >= bytes)
+ break;
+
+ /* A suitable mode should have been found. */
+ gcc_assert (mode != VOIDmode);
+ }
+
+ if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (word_mode))
+ dst_mode = word_mode;
+ else
+ dst_mode = mode;
+ dst = gen_reg_rtx (dst_mode);
+
+ for (i = 0; i < n_regs; i++)
+ emit_move_insn (operand_subword (dst, i, 0, dst_mode), dst_words[i]);
+
+ if (mode != dst_mode)
+ dst = gen_lowpart (mode, dst);
+
+ return dst;
+}
+
/* Add a USE expression for REG to the (possibly empty) list pointed
to by CALL_FUSAGE. REG must denote a hard register. */
return def_stmt;
}
+
+#ifdef HAVE_conditional_move
+/* Return the defining gimple statement for SSA_NAME NAME if it is an
+ assigment and the class of the expresion on the RHS is CLASS. Return
+ NULL otherwise. */
+
+static gimple
+get_def_for_expr_class (tree name, enum tree_code_class tclass)
+{
+ gimple def_stmt;
+
+ if (TREE_CODE (name) != SSA_NAME)
+ return NULL;
+
+ def_stmt = get_gimple_for_ssa_name (name);
+ if (!def_stmt
+ || TREE_CODE_CLASS (gimple_assign_rhs_code (def_stmt)) != tclass)
+ return NULL;
+
+ return def_stmt;
+}
+#endif
\f
/* Determine whether the LEN bytes generated by CONSTFUN can be
rtx (*constfun) (void *, HOST_WIDE_INT, enum machine_mode),
void *constfundata, unsigned int align, bool memsetp, int endp)
{
- enum machine_mode to_addr_mode
- = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to));
+ enum machine_mode to_addr_mode = get_address_mode (to);
struct store_by_pieces_d data;
if (len == 0)
emit_insn (gen_add2_insn (data.to_addr, constm1_rtx));
else
data.to_addr = copy_to_mode_reg (to_addr_mode,
- plus_constant (data.to_addr,
+ plus_constant (to_addr_mode,
+ data.to_addr,
-1));
}
to1 = adjust_automodify_address (data.to, QImode, data.to_addr,
store_by_pieces_1 (struct store_by_pieces_d *data ATTRIBUTE_UNUSED,
unsigned int align ATTRIBUTE_UNUSED)
{
- enum machine_mode to_addr_mode
- = targetm.addr_space.address_mode (MEM_ADDR_SPACE (data->to));
+ enum machine_mode to_addr_mode = get_address_mode (data->to);
rtx to_addr = XEXP (data->to, 0);
unsigned int max_size = STORE_MAX_PIECES + 1;
enum insn_code icode;
if (USE_STORE_PRE_DECREMENT (mode) && data->reverse && ! data->autinc_to)
{
data->to_addr = copy_to_mode_reg (to_addr_mode,
- plus_constant (to_addr, data->len));
+ plus_constant (to_addr_mode,
+ to_addr,
+ data->len));
data->autinc_to = 1;
data->explicit_inc_to = -1;
}
/* Emit code to copy OBJECT and SIZE into new pseudos. We can then
place those into new pseudos into a VAR_DECL and use them later. */
- object = copy_to_mode_reg (Pmode, XEXP (object, 0));
+ object = copy_addr_to_reg (XEXP (object, 0));
size_mode = TYPE_MODE (sizetype);
size = convert_to_mode (size_mode, size, 1);
}
/* A subroutine of set_storage_via_libcall. Create the tree node
- for the function we use for block clears. The first time FOR_CALL
- is true, we call assemble_external. */
+ for the function we use for block clears. */
tree block_clear_fn;
{
emitted_extern = true;
make_decl_rtl (block_clear_fn);
- assemble_external (block_clear_fn);
}
return block_clear_fn;
case POST_INC:
case POST_DEC:
case POST_MODIFY:
- temp = plus_constant (stack_pointer_rtx, -adjust);
+ temp = plus_constant (Pmode, stack_pointer_rtx, -adjust);
break;
default:
gcc_unreachable ();
size = convert_modes (Pmode, ptr_mode, size, 1);
if (CONSTANT_P (size))
- anti_adjust_stack (plus_constant (size, extra));
+ anti_adjust_stack (plus_constant (Pmode, size, extra));
else if (REG_P (size) && extra == 0)
anti_adjust_stack (size);
else
{
temp = virtual_outgoing_args_rtx;
if (extra != 0 && below)
- temp = plus_constant (temp, extra);
+ temp = plus_constant (Pmode, temp, extra);
}
else
{
if (CONST_INT_P (size))
- temp = plus_constant (virtual_outgoing_args_rtx,
+ temp = plus_constant (Pmode, virtual_outgoing_args_rtx,
-INTVAL (size) - (below ? 0 : extra));
else if (extra != 0 && !below)
temp = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx,
- negate_rtx (Pmode, plus_constant (size, extra)));
+ negate_rtx (Pmode, plus_constant (Pmode, size,
+ extra)));
else
temp = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx,
negate_rtx (Pmode, size));
(1) One or more auto-inc style memory references (aka pushes),
(2) One or more addition/subtraction with the SP as destination,
(3) A single move insn with the SP as destination,
- (4) A call_pop insn.
+ (4) A call_pop insn,
+ (5) Noreturn call insns if !ACCUMULATE_OUTGOING_ARGS.
- Insns in the sequence that do not modify the SP are ignored.
+ Insns in the sequence that do not modify the SP are ignored,
+ except for noreturn calls.
The return value is the amount of adjustment that can be trivially
verified, via immediate operand or auto-inc. If the adjustment
this_delta = find_args_size_adjust (insn);
if (this_delta == 0)
- continue;
+ {
+ if (!CALL_P (insn)
+ || ACCUMULATE_OUTGOING_ARGS
+ || find_reg_note (insn, REG_NORETURN, NULL_RTX) == NULL_RTX)
+ continue;
+ }
gcc_assert (!saw_unknown);
if (this_delta == HOST_WIDE_INT_MIN)
size = GEN_INT (GET_MODE_SIZE (mode));
if (!MEM_P (xinner))
{
- temp = assign_temp (type, 0, 1, 1);
+ temp = assign_temp (type, 1, 1);
emit_move_insn (temp, xinner);
xinner = temp;
}
}
else if (CONST_INT_P (args_so_far))
temp = memory_address (BLKmode,
- plus_constant (args_addr,
+ plus_constant (Pmode, args_addr,
skip + INTVAL (args_so_far)));
else
temp = memory_address (BLKmode,
- plus_constant (gen_rtx_PLUS (Pmode,
+ plus_constant (Pmode,
+ gen_rtx_PLUS (Pmode,
args_addr,
args_so_far),
skip));
if (CONST_INT_P (args_so_far))
addr
= memory_address (mode,
- plus_constant (args_addr,
+ plus_constant (Pmode, args_addr,
INTVAL (args_so_far)));
else
addr = memory_address (mode, gen_rtx_PLUS (Pmode, args_addr,
value = expand_and (str_mode, value, const1_rtx, NULL);
binop = xor_optab;
}
- value = expand_shift (LSHIFT_EXPR, str_mode, value,
- bitpos, NULL_RTX, 1);
+ value = expand_shift (LSHIFT_EXPR, str_mode, value, bitpos, NULL_RTX, 1);
result = expand_binop (str_mode, binop, str_rtx,
value, str_rtx, 1, OPTAB_WIDEN);
if (result != str_rtx)
case BIT_XOR_EXPR:
if (TREE_CODE (op1) != INTEGER_CST)
break;
- value = expand_expr (op1, NULL_RTX, GET_MODE (str_rtx), EXPAND_NORMAL);
- value = convert_modes (GET_MODE (str_rtx),
+ value = expand_expr (op1, NULL_RTX, str_mode, EXPAND_NORMAL);
+ value = convert_modes (str_mode,
TYPE_MODE (TREE_TYPE (op1)), value,
TYPE_UNSIGNED (TREE_TYPE (op1)));
}
binop = code == BIT_IOR_EXPR ? ior_optab : xor_optab;
- if (bitpos + bitsize != GET_MODE_BITSIZE (GET_MODE (str_rtx)))
+ if (bitpos + bitsize != str_bitsize)
{
- rtx mask = GEN_INT (((unsigned HOST_WIDE_INT) 1 << bitsize)
- - 1);
- value = expand_and (GET_MODE (str_rtx), value, mask,
- NULL_RTX);
+ rtx mask = GEN_INT (((unsigned HOST_WIDE_INT) 1 << bitsize) - 1);
+ value = expand_and (str_mode, value, mask, NULL_RTX);
}
- value = expand_shift (LSHIFT_EXPR, GET_MODE (str_rtx), value,
- bitpos, NULL_RTX, 1);
- result = expand_binop (GET_MODE (str_rtx), binop, str_rtx,
+ value = expand_shift (LSHIFT_EXPR, str_mode, value, bitpos, NULL_RTX, 1);
+ result = expand_binop (str_mode, binop, str_rtx,
value, str_rtx, 1, OPTAB_WIDEN);
if (result != str_rtx)
emit_move_insn (str_rtx, result);
/* In the C++ memory model, consecutive bit fields in a structure are
considered one memory location.
- Given a COMPONENT_REF, this function returns the bit range of
- consecutive bits in which this COMPONENT_REF belongs in. The
- values are returned in *BITSTART and *BITEND. If either the C++
- memory model is not activated, or this memory access is not thread
- visible, 0 is returned in *BITSTART and *BITEND.
-
- EXP is the COMPONENT_REF.
- INNERDECL is the actual object being referenced.
- BITPOS is the position in bits where the bit starts within the structure.
- BITSIZE is size in bits of the field being referenced in EXP.
-
- For example, while storing into FOO.A here...
+ Given a COMPONENT_REF EXP at position (BITPOS, OFFSET), this function
+ returns the bit range of consecutive bits in which this COMPONENT_REF
+ belongs. The values are returned in *BITSTART and *BITEND. *BITPOS
+ and *OFFSET may be adjusted in the process.
- struct {
- BIT 0:
- unsigned int a : 4;
- unsigned int b : 1;
- BIT 8:
- unsigned char c;
- unsigned int d : 6;
- } foo;
-
- ...we are not allowed to store past <b>, so for the layout above, a
- range of 0..7 (because no one cares if we store into the
- padding). */
+ If the access does not need to be restricted, 0 is returned in both
+ *BITSTART and *BITEND. */
static void
get_bit_range (unsigned HOST_WIDE_INT *bitstart,
unsigned HOST_WIDE_INT *bitend,
- tree exp, tree innerdecl,
- HOST_WIDE_INT bitpos, HOST_WIDE_INT bitsize)
+ tree exp,
+ HOST_WIDE_INT *bitpos,
+ tree *offset)
{
- tree field, record_type, fld;
- bool found_field = false;
- bool prev_field_is_bitfield;
+ HOST_WIDE_INT bitoffset;
+ tree field, repr;
gcc_assert (TREE_CODE (exp) == COMPONENT_REF);
- /* If other threads can't see this value, no need to restrict stores. */
- if (ALLOW_STORE_DATA_RACES
- || ((TREE_CODE (innerdecl) == MEM_REF
- || TREE_CODE (innerdecl) == TARGET_MEM_REF)
- && !ptr_deref_may_alias_global_p (TREE_OPERAND (innerdecl, 0)))
- || (DECL_P (innerdecl)
- && ((TREE_CODE (innerdecl) == VAR_DECL
- && DECL_THREAD_LOCAL_P (innerdecl))
- || !TREE_STATIC (innerdecl))))
+ field = TREE_OPERAND (exp, 1);
+ repr = DECL_BIT_FIELD_REPRESENTATIVE (field);
+ /* If we do not have a DECL_BIT_FIELD_REPRESENTATIVE there is no
+ need to limit the range we can access. */
+ if (!repr)
{
*bitstart = *bitend = 0;
return;
}
- /* Bit field we're storing into. */
- field = TREE_OPERAND (exp, 1);
- record_type = DECL_FIELD_CONTEXT (field);
-
- /* Count the contiguous bitfields for the memory location that
- contains FIELD. */
- *bitstart = 0;
- prev_field_is_bitfield = true;
- for (fld = TYPE_FIELDS (record_type); fld; fld = DECL_CHAIN (fld))
+ /* If we have a DECL_BIT_FIELD_REPRESENTATIVE but the enclosing record is
+ part of a larger bit field, then the representative does not serve any
+ useful purpose. This can occur in Ada. */
+ if (handled_component_p (TREE_OPERAND (exp, 0)))
{
- tree t, offset;
- enum machine_mode mode;
- int unsignedp, volatilep;
-
- if (TREE_CODE (fld) != FIELD_DECL)
- continue;
-
- t = build3 (COMPONENT_REF, TREE_TYPE (exp),
- unshare_expr (TREE_OPERAND (exp, 0)),
- fld, NULL_TREE);
- get_inner_reference (t, &bitsize, &bitpos, &offset,
- &mode, &unsignedp, &volatilep, true);
-
- if (field == fld)
- found_field = true;
-
- if (DECL_BIT_FIELD_TYPE (fld) && bitsize > 0)
- {
- if (prev_field_is_bitfield == false)
- {
- *bitstart = bitpos;
- prev_field_is_bitfield = true;
- }
- }
- else
+ enum machine_mode rmode;
+ HOST_WIDE_INT rbitsize, rbitpos;
+ tree roffset;
+ int unsignedp;
+ int volatilep = 0;
+ get_inner_reference (TREE_OPERAND (exp, 0), &rbitsize, &rbitpos,
+ &roffset, &rmode, &unsignedp, &volatilep, false);
+ if ((rbitpos % BITS_PER_UNIT) != 0)
{
- prev_field_is_bitfield = false;
- if (found_field)
- break;
+ *bitstart = *bitend = 0;
+ return;
}
}
- gcc_assert (found_field);
- if (fld)
- {
- /* We found the end of the bit field sequence. Include the
- padding up to the next field and be done. */
- *bitend = bitpos - 1;
- }
+ /* Compute the adjustment to bitpos from the offset of the field
+ relative to the representative. DECL_FIELD_OFFSET of field and
+ repr are the same by construction if they are not constants,
+ see finish_bitfield_layout. */
+ if (host_integerp (DECL_FIELD_OFFSET (field), 1)
+ && host_integerp (DECL_FIELD_OFFSET (repr), 1))
+ bitoffset = (tree_low_cst (DECL_FIELD_OFFSET (field), 1)
+ - tree_low_cst (DECL_FIELD_OFFSET (repr), 1)) * BITS_PER_UNIT;
else
+ bitoffset = 0;
+ bitoffset += (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
+ - tree_low_cst (DECL_FIELD_BIT_OFFSET (repr), 1));
+
+ /* If the adjustment is larger than bitpos, we would have a negative bit
+ position for the lower bound and this may wreak havoc later. This can
+ occur only if we have a non-null offset, so adjust offset and bitpos
+ to make the lower bound non-negative. */
+ if (bitoffset > *bitpos)
{
- /* If this is the last element in the structure, include the padding
- at the end of structure. */
- *bitend = TREE_INT_CST_LOW (TYPE_SIZE (record_type)) - 1;
+ HOST_WIDE_INT adjust = bitoffset - *bitpos;
+
+ gcc_assert ((adjust % BITS_PER_UNIT) == 0);
+ gcc_assert (*offset != NULL_TREE);
+
+ *bitpos += adjust;
+ *offset
+ = size_binop (MINUS_EXPR, *offset, size_int (adjust / BITS_PER_UNIT));
+ *bitstart = 0;
}
+ else
+ *bitstart = *bitpos - bitoffset;
+
+ *bitend = *bitstart + tree_low_cst (DECL_SIZE (repr), 1) - 1;
+}
+
+/* Returns true if the MEM_REF REF refers to an object that does not
+ reside in memory and has non-BLKmode. */
+
+static bool
+mem_ref_refers_to_non_mem_p (tree ref)
+{
+ tree base = TREE_OPERAND (ref, 0);
+ if (TREE_CODE (base) != ADDR_EXPR)
+ return false;
+ base = TREE_OPERAND (base, 0);
+ return (DECL_P (base)
+ && !TREE_ADDRESSABLE (base)
+ && DECL_MODE (base) != BLKmode
+ && DECL_RTL_SET_P (base)
+ && !MEM_P (DECL_RTL (base)));
}
/* Expand an assignment that stores the value of FROM into TO. If NONTEMPORAL
rtx to_rtx = 0;
rtx result;
enum machine_mode mode;
- int align;
+ unsigned int align;
enum insn_code icode;
/* Don't crash if the lhs of the assignment was erroneous. */
if (operand_equal_p (to, from, 0))
return;
+ /* Handle misaligned stores. */
mode = TYPE_MODE (TREE_TYPE (to));
if ((TREE_CODE (to) == MEM_REF
|| TREE_CODE (to) == TARGET_MEM_REF)
&& mode != BLKmode
- && ((align = MAX (TYPE_ALIGN (TREE_TYPE (to)), get_object_alignment (to)))
- < (signed) GET_MODE_ALIGNMENT (mode))
- && ((icode = optab_handler (movmisalign_optab, mode))
- != CODE_FOR_nothing))
+ && !mem_ref_refers_to_non_mem_p (to)
+ && ((align = get_object_or_type_alignment (to))
+ < GET_MODE_ALIGNMENT (mode))
+ && (((icode = optab_handler (movmisalign_optab, mode))
+ != CODE_FOR_nothing)
+ || SLOW_UNALIGNED_ACCESS (mode, align)))
{
- struct expand_operand ops[2];
- enum machine_mode address_mode;
- rtx reg, op0, mem;
+ rtx reg, mem;
reg = expand_expr (from, NULL_RTX, VOIDmode, EXPAND_NORMAL);
reg = force_not_mem (reg);
+ mem = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_WRITE);
- if (TREE_CODE (to) == MEM_REF)
- {
- addr_space_t as
- = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (to, 1))));
- tree base = TREE_OPERAND (to, 0);
- address_mode = targetm.addr_space.address_mode (as);
- op0 = expand_expr (base, NULL_RTX, VOIDmode, EXPAND_NORMAL);
- op0 = convert_memory_address_addr_space (address_mode, op0, as);
- if (!integer_zerop (TREE_OPERAND (to, 1)))
- {
- rtx off
- = immed_double_int_const (mem_ref_offset (to), address_mode);
- op0 = simplify_gen_binary (PLUS, address_mode, op0, off);
- }
- op0 = memory_address_addr_space (mode, op0, as);
- mem = gen_rtx_MEM (mode, op0);
- set_mem_attributes (mem, to, 0);
- set_mem_addr_space (mem, as);
- }
- else if (TREE_CODE (to) == TARGET_MEM_REF)
+ if (icode != CODE_FOR_nothing)
{
- addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (to));
- struct mem_address addr;
+ struct expand_operand ops[2];
- get_address_description (to, &addr);
- op0 = addr_for_mem_ref (&addr, as, true);
- op0 = memory_address_addr_space (mode, op0, as);
- mem = gen_rtx_MEM (mode, op0);
- set_mem_attributes (mem, to, 0);
- set_mem_addr_space (mem, as);
+ create_fixed_operand (&ops[0], mem);
+ create_input_operand (&ops[1], reg, mode);
+ /* The movmisalign<mode> pattern cannot fail, else the assignment
+ would silently be omitted. */
+ expand_insn (icode, 2, ops);
}
else
- gcc_unreachable ();
- if (TREE_THIS_VOLATILE (to))
- MEM_VOLATILE_P (mem) = 1;
-
- create_fixed_operand (&ops[0], mem);
- create_input_operand (&ops[1], reg, mode);
- /* The movmisalign<mode> pattern cannot fail, else the assignment would
- silently be omitted. */
- expand_insn (icode, 2, ops);
+ store_bit_field (mem, GET_MODE_BITSIZE (mode),
+ 0, 0, 0, mode, reg);
return;
}
if the structure component's rtx is not simply a MEM.
Assignment of an array element at a constant index, and assignment of
an array element in an unaligned packed structure field, has the same
- problem. */
+ problem. Same for (partially) storing into a non-memory object. */
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)
+ && mem_ref_refers_to_non_mem_p (to))
|| TREE_CODE (TREE_TYPE (to)) == ARRAY_TYPE)
{
enum machine_mode mode1;
int unsignedp;
int volatilep = 0;
tree tem;
+ bool misalignp;
+ rtx mem = NULL_RTX;
push_temp_slots ();
tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1,
if (TREE_CODE (to) == COMPONENT_REF
&& DECL_BIT_FIELD_TYPE (TREE_OPERAND (to, 1)))
- get_bit_range (&bitregion_start, &bitregion_end,
- to, tem, bitpos, bitsize);
+ get_bit_range (&bitregion_start, &bitregion_end, to, &bitpos, &offset);
/* If we are going to use store_bit_field and extract_bit_field,
make sure to_rtx will be safe for multiple use. */
+ mode = TYPE_MODE (TREE_TYPE (tem));
+ if (TREE_CODE (tem) == MEM_REF
+ && mode != BLKmode
+ && ((align = get_object_or_type_alignment (tem))
+ < GET_MODE_ALIGNMENT (mode))
+ && ((icode = optab_handler (movmisalign_optab, mode))
+ != CODE_FOR_nothing))
+ {
+ struct expand_operand ops[2];
+
+ misalignp = true;
+ to_rtx = gen_reg_rtx (mode);
+ mem = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_WRITE);
+
+ /* If the misaligned store doesn't overwrite all bits, perform
+ rmw cycle on MEM. */
+ if (bitsize != GET_MODE_BITSIZE (mode))
+ {
+ create_input_operand (&ops[0], to_rtx, mode);
+ create_fixed_operand (&ops[1], mem);
+ /* The movmisalign<mode> pattern cannot fail, else the assignment
+ would silently be omitted. */
+ expand_insn (icode, 2, ops);
- to_rtx = expand_normal (tem);
+ mem = copy_rtx (mem);
+ }
+ }
+ else
+ {
+ misalignp = false;
+ to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_WRITE);
+ }
/* If the bitfield is volatile, we want to access it in the
field's mode, not the computed mode.
}
offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
- address_mode
- = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to_rtx));
+ address_mode = get_address_mode (to_rtx);
if (GET_MODE (offset_rtx) != address_mode)
offset_rtx = convert_to_mode (address_mode, offset_rtx, 0);
else
{
rtx temp = assign_stack_temp (GET_MODE (to_rtx),
- GET_MODE_SIZE (GET_MODE (to_rtx)),
- 0);
+ GET_MODE_SIZE (GET_MODE (to_rtx)));
write_complex_part (temp, XEXP (to_rtx, 0), false);
write_complex_part (temp, XEXP (to_rtx, 1), true);
result = store_field (temp, bitsize, bitpos,
nontemporal);
}
+ if (misalignp)
+ {
+ struct expand_operand ops[2];
+
+ create_fixed_operand (&ops[0], mem);
+ create_input_operand (&ops[1], to_rtx, mode);
+ /* The movmisalign<mode> pattern cannot fail, else the assignment
+ would silently be omitted. */
+ expand_insn (icode, 2, ops);
+ }
+
if (result)
preserve_temp_slots (result);
- free_temp_slots ();
pop_temp_slots ();
return;
}
if (TREE_CODE (from) == CALL_EXPR && ! aggregate_value_p (from, from)
&& COMPLETE_TYPE_P (TREE_TYPE (from))
&& TREE_CODE (TYPE_SIZE (TREE_TYPE (from))) == INTEGER_CST
- && ! (((TREE_CODE (to) == VAR_DECL || TREE_CODE (to) == PARM_DECL)
+ && ! (((TREE_CODE (to) == VAR_DECL
+ || TREE_CODE (to) == PARM_DECL
+ || TREE_CODE (to) == RESULT_DECL)
&& REG_P (DECL_RTL (to)))
|| TREE_CODE (to) == SSA_NAME))
{
emit_move_insn (to_rtx, value);
}
preserve_temp_slots (to_rtx);
- free_temp_slots ();
pop_temp_slots ();
return;
}
- /* Ordinary treatment. Expand TO to get a REG or MEM rtx.
- Don't re-expand if it was expanded already (in COMPONENT_REF case). */
-
- if (to_rtx == 0)
- to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_WRITE);
+ /* Ordinary treatment. Expand TO to get a REG or MEM rtx. */
+ to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_WRITE);
/* Don't move directly into a return register. */
if (TREE_CODE (to) == RESULT_DECL
rtx temp;
push_temp_slots ();
- temp = expand_expr (from, NULL_RTX, GET_MODE (to_rtx), EXPAND_NORMAL);
+ if (REG_P (to_rtx) && TYPE_MODE (TREE_TYPE (from)) == BLKmode)
+ temp = copy_blkmode_to_reg (GET_MODE (to_rtx), from);
+ else
+ temp = expand_expr (from, NULL_RTX, GET_MODE (to_rtx), EXPAND_NORMAL);
if (GET_CODE (to_rtx) == PARALLEL)
emit_group_load (to_rtx, temp, TREE_TYPE (from),
int_size_in_bytes (TREE_TYPE (from)));
- else
+ else if (temp)
emit_move_insn (to_rtx, temp);
preserve_temp_slots (to_rtx);
- free_temp_slots ();
pop_temp_slots ();
return;
}
TYPE_MODE (sizetype));
preserve_temp_slots (to_rtx);
- free_temp_slots ();
pop_temp_slots ();
return;
}
push_temp_slots ();
result = store_expr (from, to_rtx, 0, nontemporal);
preserve_temp_slots (result);
- free_temp_slots ();
pop_temp_slots ();
return;
}
{
enum machine_mode pointer_mode
= targetm.addr_space.pointer_mode (MEM_ADDR_SPACE (target));
- enum machine_mode address_mode
- = targetm.addr_space.address_mode (MEM_ADDR_SPACE (target));
+ enum machine_mode address_mode = get_address_mode (target);
/* Compute the size of the data to copy from the string. */
tree copy_size
Do all calculations in pointer_mode. */
if (CONST_INT_P (copy_size_rtx))
{
- size = plus_constant (size, -INTVAL (copy_size_rtx));
+ size = plus_constant (address_mode, size,
+ -INTVAL (copy_size_rtx));
target = adjust_address (target, BLKmode,
INTVAL (copy_size_rtx));
}
case VECTOR_CST:
{
- tree v;
- for (v = TREE_VECTOR_CST_ELTS (value); v; v = TREE_CHAIN (v))
+ unsigned i;
+ for (i = 0; i < VECTOR_CST_NELTS (value); ++i)
{
- if (!initializer_zerop (TREE_VALUE (v)))
+ tree v = VECTOR_CST_ELT (value, i);
+ if (!initializer_zerop (v))
nz_elts += mult;
init_elts += mult;
}
offset_rtx = expand_normal (offset);
gcc_assert (MEM_P (to_rtx));
- address_mode
- = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to_rtx));
+ address_mode = get_address_mode (to_rtx);
if (GET_MODE (offset_rtx) != address_mode)
offset_rtx = convert_to_mode (address_mode, offset_rtx, 0);
if (TYPE_PRECISION (type) < BITS_PER_WORD)
{
- type = lang_hooks.types.type_for_size
- (BITS_PER_WORD, TYPE_UNSIGNED (type));
+ type = lang_hooks.types.type_for_mode
+ (word_mode, TYPE_UNSIGNED (type));
value = fold_convert (type, value);
}
if (mode == BLKmode
&& (REG_P (target) || GET_CODE (target) == SUBREG))
{
- rtx object = assign_temp (type, 0, 1, 1);
+ rtx object = assign_temp (type, 1, 1);
rtx blk_object = adjust_address (object, BLKmode, 0);
if (bitsize != (HOST_WIDE_INT) GET_MODE_BITSIZE (GET_MODE (target)))
store_field (blk_object, bitsize, bitpos,
bitregion_start, bitregion_end,
- mode, exp, type, alias_set, nontemporal);
+ mode, exp, type, MEM_ALIAS_SET (blk_object), nontemporal);
emit_move_insn (target, object);
|| bitpos % GET_MODE_ALIGNMENT (mode))
&& SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (target)))
|| (bitpos % BITS_PER_UNIT != 0)))
+ || (bitsize >= 0 && mode != BLKmode
+ && GET_MODE_BITSIZE (mode) > bitsize)
/* If the RHS and field are a constant size and the size of the
RHS isn't the same size as the bitfield, we must use bitfield
operations. */
GET_MODE_BITSIZE (GET_MODE (temp)) - bitsize,
NULL_RTX, 1);
- /* Unless MODE is VOIDmode or BLKmode, convert TEMP to
- MODE. */
+ /* Unless MODE is VOIDmode or BLKmode, convert TEMP to MODE. */
if (mode != VOIDmode && mode != BLKmode
&& mode != TYPE_MODE (TREE_TYPE (exp)))
temp = convert_modes (mode, TYPE_MODE (TREE_TYPE (exp)), temp, 1);
if (to_rtx == target)
to_rtx = copy_rtx (to_rtx);
- if (!MEM_SCALAR_P (to_rtx))
- MEM_IN_STRUCT_P (to_rtx) = 1;
if (!MEM_KEEP_ALIAS_SET_P (to_rtx) && MEM_ALIAS_SET (to_rtx) != 0)
set_mem_alias_set (to_rtx, alias_set);
/* Otherwise, split it up. */
if (offset)
{
+ /* Avoid returning a negative bitpos as this may wreak havoc later. */
+ if (double_int_negative_p (bit_offset))
+ {
+ double_int mask
+ = double_int_mask (BITS_PER_UNIT == 8
+ ? 3 : exact_log2 (BITS_PER_UNIT));
+ double_int tem = double_int_and_not (bit_offset, mask);
+ /* TEM is the bitpos rounded to BITS_PER_UNIT towards -Inf.
+ Subtract it to BIT_OFFSET and add it (scaled) to OFFSET. */
+ bit_offset = double_int_sub (bit_offset, tem);
+ tem = double_int_rshift (tem,
+ BITS_PER_UNIT == 8
+ ? 3 : exact_log2 (BITS_PER_UNIT),
+ HOST_BITS_PER_DOUBLE_INT, true);
+ offset = size_binop (PLUS_EXPR, offset,
+ double_int_to_tree (sizetype, tem));
+ }
+
*pbitpos = double_int_to_shwi (bit_offset);
*poffset = offset;
}
return build_int_cst (TREE_TYPE (TREE_OPERAND (exp, 1)), 0);
}
+/* Returns true if REF is an array reference to an array at the end of
+ a structure. If this is the case, the array may be allocated larger
+ than its upper bound implies. */
+
+bool
+array_at_struct_end_p (tree ref)
+{
+ if (TREE_CODE (ref) != ARRAY_REF
+ && TREE_CODE (ref) != ARRAY_RANGE_REF)
+ return false;
+
+ while (handled_component_p (ref))
+ {
+ /* If the reference chain contains a component reference to a
+ non-union type and there follows another field the reference
+ is not at the end of a structure. */
+ if (TREE_CODE (ref) == COMPONENT_REF
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 0))) == RECORD_TYPE)
+ {
+ tree nextf = DECL_CHAIN (TREE_OPERAND (ref, 1));
+ while (nextf && TREE_CODE (nextf) != FIELD_DECL)
+ nextf = DECL_CHAIN (nextf);
+ if (nextf)
+ return false;
+ }
+
+ ref = TREE_OPERAND (ref, 0);
+ }
+
+ /* If the reference is based on a declared entity, the size of the array
+ is constrained by its given domain. */
+ if (DECL_P (ref))
+ return false;
+
+ return true;
+}
+
/* Return a tree representing the upper bound of the array mentioned in
EXP, an ARRAY_REF or an ARRAY_RANGE_REF. */
are memory and they conflict. */
return ! (rtx_equal_p (x, exp_rtl)
|| (MEM_P (x) && MEM_P (exp_rtl)
- && true_dependence (exp_rtl, VOIDmode, x,
- rtx_addr_varies_p)));
+ && true_dependence (exp_rtl, VOIDmode, x)));
}
/* If we reach here, it is safe. */
return MAX (factor, talign);
}
\f
+#ifdef HAVE_conditional_move
+/* Convert the tree comparison code TCODE to the rtl one where the
+ signedness is UNSIGNEDP. */
+
+static enum rtx_code
+convert_tree_comp_to_rtx (enum tree_code tcode, int unsignedp)
+{
+ enum rtx_code code;
+ switch (tcode)
+ {
+ case EQ_EXPR:
+ code = EQ;
+ break;
+ case NE_EXPR:
+ code = NE;
+ break;
+ case LT_EXPR:
+ code = unsignedp ? LTU : LT;
+ break;
+ case LE_EXPR:
+ code = unsignedp ? LEU : LE;
+ break;
+ case GT_EXPR:
+ code = unsignedp ? GTU : GT;
+ break;
+ case GE_EXPR:
+ code = unsignedp ? GEU : GE;
+ break;
+ case UNORDERED_EXPR:
+ code = UNORDERED;
+ break;
+ case ORDERED_EXPR:
+ code = ORDERED;
+ break;
+ case UNLT_EXPR:
+ code = UNLT;
+ break;
+ case UNLE_EXPR:
+ code = UNLE;
+ break;
+ case UNGT_EXPR:
+ code = UNGT;
+ break;
+ case UNGE_EXPR:
+ code = UNGE;
+ break;
+ case UNEQ_EXPR:
+ code = UNEQ;
+ break;
+ case LTGT_EXPR:
+ code = LTGT;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ return code;
+}
+#endif
+
/* Subroutine of expand_expr. Expand the two operands of a binary
expression EXP0 and EXP1 placing the results in OP0 and OP1.
The value may be stored in TARGET if TARGET is nonzero. The
generating ADDR_EXPR of something that isn't an LVALUE. The only
exception here is STRING_CST. */
if (CONSTANT_CLASS_P (exp))
- return XEXP (expand_expr_constant (exp, 0, modifier), 0);
+ {
+ result = XEXP (expand_expr_constant (exp, 0, modifier), 0);
+ if (modifier < EXPAND_SUM)
+ result = force_operand (result, target);
+ return result;
+ }
/* Everything must be something allowed by is_gimple_addressable. */
switch (TREE_CODE (exp))
case CONST_DECL:
/* Expand the initializer like constants above. */
- return XEXP (expand_expr_constant (DECL_INITIAL (exp), 0, modifier), 0);
+ result = XEXP (expand_expr_constant (DECL_INITIAL (exp),
+ 0, modifier), 0);
+ if (modifier < EXPAND_SUM)
+ result = force_operand (result, target);
+ return result;
case REALPART_EXPR:
/* The real part of the complex number is always first, therefore
result = XEXP (result, 0);
/* ??? Is this needed anymore? */
- if (DECL_P (exp) && !TREE_USED (exp) == 0)
- {
- assemble_external (exp);
- TREE_USED (exp) = 1;
- }
+ if (DECL_P (exp))
+ TREE_USED (exp) = 1;
if (modifier != EXPAND_INITIALIZER
- && modifier != EXPAND_CONST_ADDRESS)
+ && modifier != EXPAND_CONST_ADDRESS
+ && modifier != EXPAND_SUM)
result = force_operand (result, target);
return result;
}
of such an object. */
gcc_assert ((bitpos % BITS_PER_UNIT) == 0);
- result = plus_constant (result, bitpos / BITS_PER_UNIT);
+ result = plus_constant (tmode, result, bitpos / BITS_PER_UNIT);
if (modifier < EXPAND_SUM)
result = force_operand (result, target);
}
= assign_temp (build_qualified_type (type, (TYPE_QUALS (type)
| (TREE_READONLY (exp)
* TYPE_QUAL_CONST))),
- 0, TREE_ADDRESSABLE (exp), 1);
+ TREE_ADDRESSABLE (exp), 1);
}
store_constructor (exp, target, 0, int_expr_size (exp));
return ret;
}
+/* Try to expand the conditional expression which is represented by
+ TREEOP0 ? TREEOP1 : TREEOP2 using conditonal moves. If succeseds
+ return the rtl reg which repsents the result. Otherwise return
+ NULL_RTL. */
+
+static rtx
+expand_cond_expr_using_cmove (tree treeop0 ATTRIBUTE_UNUSED,
+ tree treeop1 ATTRIBUTE_UNUSED,
+ tree treeop2 ATTRIBUTE_UNUSED)
+{
+#ifdef HAVE_conditional_move
+ rtx insn;
+ rtx op00, op01, op1, op2;
+ enum rtx_code comparison_code;
+ enum machine_mode comparison_mode;
+ gimple srcstmt;
+ rtx temp;
+ tree type = TREE_TYPE (treeop1);
+ int unsignedp = TYPE_UNSIGNED (type);
+ enum machine_mode mode = TYPE_MODE (type);
+
+ temp = assign_temp (type, 0, 1);
+
+ /* If we cannot do a conditional move on the mode, try doing it
+ with the promoted mode. */
+ if (!can_conditionally_move_p (mode))
+ mode = promote_mode (type, mode, &unsignedp);
+
+ if (!can_conditionally_move_p (mode))
+ return NULL_RTX;
+
+ start_sequence ();
+ expand_operands (treeop1, treeop2,
+ temp, &op1, &op2, EXPAND_NORMAL);
+
+ if (TREE_CODE (treeop0) == SSA_NAME
+ && (srcstmt = get_def_for_expr_class (treeop0, tcc_comparison)))
+ {
+ tree type = TREE_TYPE (gimple_assign_rhs1 (srcstmt));
+ enum tree_code cmpcode = gimple_assign_rhs_code (srcstmt);
+ op00 = expand_normal (gimple_assign_rhs1 (srcstmt));
+ op01 = expand_normal (gimple_assign_rhs2 (srcstmt));
+ comparison_mode = TYPE_MODE (type);
+ unsignedp = TYPE_UNSIGNED (type);
+ comparison_code = convert_tree_comp_to_rtx (cmpcode, unsignedp);
+ }
+ else if (TREE_CODE_CLASS (TREE_CODE (treeop0)) == tcc_comparison)
+ {
+ tree type = TREE_TYPE (TREE_OPERAND (treeop0, 0));
+ enum tree_code cmpcode = TREE_CODE (treeop0);
+ op00 = expand_normal (TREE_OPERAND (treeop0, 0));
+ op01 = expand_normal (TREE_OPERAND (treeop0, 1));
+ unsignedp = TYPE_UNSIGNED (type);
+ comparison_mode = TYPE_MODE (type);
+ comparison_code = convert_tree_comp_to_rtx (cmpcode, unsignedp);
+ }
+ else
+ {
+ op00 = expand_normal (treeop0);
+ op01 = const0_rtx;
+ comparison_code = NE;
+ comparison_mode = TYPE_MODE (TREE_TYPE (treeop0));
+ }
+
+ if (GET_MODE (op1) != mode)
+ op1 = gen_lowpart (mode, op1);
+
+ if (GET_MODE (op2) != mode)
+ op2 = gen_lowpart (mode, op2);
+
+ /* Try to emit the conditional move. */
+ insn = emit_conditional_move (temp, comparison_code,
+ op00, op01, comparison_mode,
+ op1, op2, 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 temp;
+ }
+
+ /* Otherwise discard the sequence and fall back to code with
+ branches. */
+ end_sequence ();
+#endif
+ return NULL_RTX;
+}
+
rtx
expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
enum expand_modifier modifier)
if (TYPE_MODE (type) != BLKmode)
target = gen_reg_rtx (TYPE_MODE (type));
else
- target = assign_temp (type, 0, 1, 1);
+ target = assign_temp (type, 1, 1);
}
if (MEM_P (target))
treeop1 = fold_convert_loc (loc, type,
fold_convert_loc (loc, ssizetype,
treeop1));
+ /* If sizetype precision is larger than pointer precision, truncate the
+ offset to have matching modes. */
+ else if (TYPE_PRECISION (sizetype) > TYPE_PRECISION (type))
+ treeop1 = fold_convert_loc (loc, type, treeop1);
+
case PLUS_EXPR:
/* 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
|| DECL_RTL (treeop1) == stack_pointer_rtx
|| DECL_RTL (treeop1) == arg_pointer_rtx))
{
- tree t = treeop1;
-
- treeop1 = TREE_OPERAND (treeop0, 0);
- TREE_OPERAND (treeop0, 0) = t;
+ gcc_unreachable ();
}
/* If the result is to be ptr_mode and we are adding an integer to
= immed_double_const (TREE_INT_CST_LOW (treeop0),
(HOST_WIDE_INT) 0,
TYPE_MODE (TREE_TYPE (treeop1)));
- op1 = plus_constant (op1, INTVAL (constant_part));
+ op1 = plus_constant (mode, op1, INTVAL (constant_part));
if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
op1 = force_operand (op1, target);
return REDUCE_BIT_FIELD (op1);
= immed_double_const (TREE_INT_CST_LOW (treeop1),
(HOST_WIDE_INT) 0,
TYPE_MODE (TREE_TYPE (treeop0)));
- op0 = plus_constant (op0, INTVAL (constant_part));
+ op0 = plus_constant (mode, op0, INTVAL (constant_part));
if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
op0 = force_operand (op0, target);
return REDUCE_BIT_FIELD (op0);
/* If the last operand is a CONST_INT, use plus_constant of
the negated constant. Else make the MINUS. */
if (CONST_INT_P (op1))
- return REDUCE_BIT_FIELD (plus_constant (op0, - INTVAL (op1)));
+ return REDUCE_BIT_FIELD (plus_constant (mode, op0,
+ -INTVAL (op1)));
else
return REDUCE_BIT_FIELD (gen_rtx_MINUS (mode, op0, op1));
}
if (modifier == EXPAND_STACK_PARM)
target = 0;
/* In case we have to reduce the result to bitfield precision
- expand this as XOR with a proper constant instead. */
- if (reduce_bit_field)
+ for unsigned bitfield expand this as XOR with a proper constant
+ instead. */
+ if (reduce_bit_field && TYPE_UNSIGNED (type))
temp = expand_binop (mode, xor_optab, op0,
immed_double_int_const
(double_int_mask (TYPE_PRECISION (type)), mode),
return temp;
}
- case VEC_EXTRACT_EVEN_EXPR:
- case VEC_EXTRACT_ODD_EXPR:
- {
- expand_operands (treeop0, treeop1,
- NULL_RTX, &op0, &op1, EXPAND_NORMAL);
- this_optab = optab_for_tree_code (code, type, optab_default);
- temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
- OPTAB_WIDEN);
- gcc_assert (temp);
- return temp;
- }
-
- case VEC_INTERLEAVE_HIGH_EXPR:
- case VEC_INTERLEAVE_LOW_EXPR:
- {
- expand_operands (treeop0, treeop1,
- NULL_RTX, &op0, &op1, EXPAND_NORMAL);
- this_optab = optab_for_tree_code (code, type, optab_default);
- temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
- OPTAB_WIDEN);
- gcc_assert (temp);
- return temp;
- }
-
case VEC_LSHIFT_EXPR:
case VEC_RSHIFT_EXPR:
{
return target;
}
+ case VEC_WIDEN_LSHIFT_HI_EXPR:
+ case VEC_WIDEN_LSHIFT_LO_EXPR:
+ {
+ tree oprnd0 = treeop0;
+ tree oprnd1 = treeop1;
+
+ expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+ target = expand_widen_pattern_expr (ops, op0, op1, NULL_RTX,
+ target, unsignedp);
+ gcc_assert (target);
+ return target;
+ }
+
case VEC_PACK_TRUNC_EXPR:
case VEC_PACK_SAT_EXPR:
case VEC_PACK_FIX_TRUNC_EXPR:
goto binop;
case VEC_PERM_EXPR:
- target = expand_vec_perm_expr (type, treeop0, treeop1, treeop2, target);
- gcc_assert (target);
- return target;
+ expand_operands (treeop0, treeop1, target, &op0, &op1, EXPAND_NORMAL);
+ op2 = expand_normal (treeop2);
+
+ /* Careful here: if the target doesn't support integral vector modes,
+ a constant selection vector could wind up smooshed into a normal
+ integral constant. */
+ if (CONSTANT_P (op2) && GET_CODE (op2) != CONST_VECTOR)
+ {
+ tree sel_type = TREE_TYPE (treeop2);
+ enum machine_mode vmode
+ = mode_for_vector (TYPE_MODE (TREE_TYPE (sel_type)),
+ TYPE_VECTOR_SUBPARTS (sel_type));
+ gcc_assert (GET_MODE_CLASS (vmode) == MODE_VECTOR_INT);
+ op2 = simplify_subreg (vmode, op2, TYPE_MODE (sel_type), 0);
+ gcc_assert (op2 && GET_CODE (op2) == CONST_VECTOR);
+ }
+ else
+ gcc_assert (GET_MODE_CLASS (GET_MODE (op2)) == MODE_VECTOR_INT);
+
+ temp = expand_vec_perm (mode, op0, op1, op2, target);
+ gcc_assert (temp);
+ return temp;
case DOT_PROD_EXPR:
{
&& TREE_TYPE (treeop1) != void_type_node
&& TREE_TYPE (treeop2) != void_type_node);
+ temp = expand_cond_expr_using_cmove (treeop0, treeop1, treeop2);
+ if (temp)
+ return temp;
+
/* If we are not to produce a result, we have no target. Otherwise,
if a target was specified use it; it will not be used as an
intermediate target unless it is safe. If no target, use a
&& original_target
&& safe_from_p (original_target, treeop0, 1)
&& GET_MODE (original_target) == mode
-#ifdef HAVE_conditional_move
- && (! can_conditionally_move_p (mode)
- || REG_P (original_target))
-#endif
&& !MEM_P (original_target))
temp = original_target;
else
- temp = assign_temp (type, 0, 0, 1);
+ temp = assign_temp (type, 0, 1);
do_pending_stack_adjust ();
NO_DEFER_POP;
&& stmt_is_replaceable_p (SSA_NAME_DEF_STMT (exp)))
g = SSA_NAME_DEF_STMT (exp);
if (g)
- return expand_expr_real (gimple_assign_rhs_to_tree (g), target, tmode,
- modifier, NULL);
+ {
+ rtx r = expand_expr_real (gimple_assign_rhs_to_tree (g), target,
+ tmode, modifier, NULL);
+ if (REG_P (r) && !REG_EXPR (r))
+ set_reg_attrs_for_decl_rtl (SSA_NAME_VAR (exp), r);
+ return r;
+ }
ssa_name = exp;
decl_rtl = get_rtx_for_ssa_name (ssa_name);
/* 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
definition. */
- if (! TREE_USED (exp))
- {
- assemble_external (exp);
- TREE_USED (exp) = 1;
- }
+ TREE_USED (exp) = 1;
/* Show we haven't gotten RTL for this yet. */
temp = 0;
/* This is the case of an array whose size is to be determined
from its initializer, while the initializer is still being parsed.
- See expand_decl. */
+ ??? We aren't parsing while expanding anymore. */
if (MEM_P (decl_rtl) && REG_P (XEXP (decl_rtl, 0)))
temp = validize_mem (decl_rtl);
return temp;
}
- /* 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 the mode of DECL_RTL does not match that of the decl,
+ there are two cases: we are dealing with a BLKmode value
+ that is returned in a register, or we are dealing with
+ a promoted value. In the latter case, return a SUBREG
+ of the wanted mode, but mark it so that we know that it
+ was already extended. */
+ if (REG_P (decl_rtl)
+ && DECL_MODE (exp) != BLKmode
+ && GET_MODE (decl_rtl) != DECL_MODE (exp))
{
enum machine_mode pmode;
tmp = fold_unary_loc (loc, VIEW_CONVERT_EXPR, type_for_mode, exp);
}
if (!tmp)
- tmp = build_constructor_from_list (type,
- TREE_VECTOR_CST_ELTS (exp));
+ {
+ VEC(constructor_elt,gc) *v;
+ unsigned i;
+ v = VEC_alloc (constructor_elt, gc, VECTOR_CST_NELTS (exp));
+ for (i = 0; i < VECTOR_CST_NELTS (exp); ++i)
+ CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, VECTOR_CST_ELT (exp, i));
+ tmp = build_constructor (type, v);
+ }
return expand_expr (tmp, ignore ? const0_rtx : target,
tmode, modifier);
}
case TARGET_MEM_REF:
{
- addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (exp));
+ addr_space_t as
+ = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))));
struct mem_address addr;
enum insn_code icode;
- int align;
+ unsigned int align;
get_address_description (exp, &addr);
op0 = addr_for_mem_ref (&addr, as, true);
temp = gen_rtx_MEM (mode, op0);
set_mem_attributes (temp, exp, 0);
set_mem_addr_space (temp, as);
- align = MAX (TYPE_ALIGN (TREE_TYPE (exp)), get_object_alignment (exp));
- if (mode != BLKmode
- && (unsigned) align < GET_MODE_ALIGNMENT (mode)
+ align = get_object_or_type_alignment (exp);
+ if (modifier != EXPAND_WRITE
+ && mode != BLKmode
+ && align < GET_MODE_ALIGNMENT (mode)
/* If the target does not have special handling for unaligned
loads of mode then it can use regular moves for them. */
&& ((icode = optab_handler (movmisalign_optab, mode))
case MEM_REF:
{
addr_space_t as
- = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1))));
+ = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))));
enum machine_mode address_mode;
tree base = TREE_OPERAND (exp, 0);
gimple def_stmt;
enum insn_code icode;
- int align;
+ unsigned align;
/* Handle expansion of non-aliased memory with non-BLKmode. That
might end up in a register. */
- if (TREE_CODE (base) == ADDR_EXPR)
+ if (mem_ref_refers_to_non_mem_p (exp))
{
HOST_WIDE_INT offset = mem_ref_offset (exp).low;
tree bit_offset;
+ tree bftype;
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)))
+ 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);
+ else
{
- 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);
+ temp = assign_stack_temp (DECL_MODE (base),
+ GET_MODE_SIZE (DECL_MODE (base)));
+ store_expr (base, temp, 0, false);
+ temp = adjust_address (temp, BLKmode, offset);
+ set_mem_size (temp, int_size_in_bytes (TREE_TYPE (exp)));
+ return temp;
}
+ 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);
gimple_assign_rhs1 (def_stmt), mask);
TREE_OPERAND (exp, 0) = base;
}
- align = MAX (TYPE_ALIGN (TREE_TYPE (exp)), get_object_alignment (exp));
+ align = get_object_or_type_alignment (exp);
op0 = expand_expr (base, NULL_RTX, VOIDmode, EXPAND_SUM);
op0 = memory_address_addr_space (address_mode, op0, as);
if (!integer_zerop (TREE_OPERAND (exp, 1)))
set_mem_addr_space (temp, as);
if (TREE_THIS_VOLATILE (exp))
MEM_VOLATILE_P (temp) = 1;
- if (mode != BLKmode
- && (unsigned) align < GET_MODE_ALIGNMENT (mode)
- /* If the target does not have special handling for unaligned
- loads of mode then it can use regular moves for them. */
- && ((icode = optab_handler (movmisalign_optab, mode))
- != CODE_FOR_nothing))
+ if (modifier != EXPAND_WRITE
+ && mode != BLKmode
+ && align < GET_MODE_ALIGNMENT (mode))
{
- struct expand_operand ops[2];
-
- /* We've already validated the memory, and we're creating a
- new pseudo destination. The predicates really can't fail,
- nor can the generator. */
- create_output_operand (&ops[0], NULL_RTX, mode);
- create_fixed_operand (&ops[1], temp);
- expand_insn (icode, 2, ops);
- return ops[0].value;
+ if ((icode = optab_handler (movmisalign_optab, mode))
+ != CODE_FOR_nothing)
+ {
+ struct expand_operand ops[2];
+
+ /* We've already validated the memory, and we're creating a
+ new pseudo destination. The predicates really can't fail,
+ nor can the generator. */
+ create_output_operand (&ops[0], NULL_RTX, mode);
+ create_fixed_operand (&ops[1], temp);
+ expand_insn (icode, 2, ops);
+ return ops[0].value;
+ }
+ else if (SLOW_UNALIGNED_ACCESS (mode, align))
+ temp = extract_bit_field (temp, GET_MODE_BITSIZE (mode),
+ 0, TYPE_UNSIGNED (TREE_TYPE (exp)),
+ true, (modifier == EXPAND_STACK_PARM
+ ? NULL_RTX : target),
+ mode, mode);
}
return temp;
}
tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
&mode1, &unsignedp, &volatilep, true);
rtx orig_op0, memloc;
+ bool mem_attrs_from_type = false;
/* If we got back the original object, something is wrong. Perhaps
we are evaluating an expression too early. In any event, don't
tree nt = build_qualified_type (TREE_TYPE (tem),
(TYPE_QUALS (TREE_TYPE (tem))
| TYPE_QUAL_CONST));
- memloc = assign_temp (nt, 1, 1, 1);
+ memloc = assign_temp (nt, 1, 1);
emit_move_insn (memloc, op0);
op0 = memloc;
+ mem_attrs_from_type = true;
}
if (offset)
gcc_assert (MEM_P (op0));
- address_mode
- = targetm.addr_space.address_mode (MEM_ADDR_SPACE (op0));
+ address_mode = get_address_mode (op0);
if (GET_MODE (offset_rtx) != address_mode)
offset_rtx = convert_to_mode (address_mode, offset_rtx, 0);
&& modifier != EXPAND_CONST_ADDRESS
&& modifier != EXPAND_INITIALIZER)
/* If the field is volatile, we always want an aligned
- access. Only do this if the access is not already naturally
+ access. Do this in following two situations:
+ 1. the access is not already naturally
aligned, otherwise "normal" (non-bitfield) volatile fields
- become non-addressable. */
+ become non-addressable.
+ 2. the bitsize is narrower than the access size. Need
+ to extract bitfields from the access. */
|| (volatilep && flag_strict_volatile_bitfields > 0
- && (bitpos % GET_MODE_ALIGNMENT (mode) != 0))
+ && (bitpos % GET_MODE_ALIGNMENT (mode) != 0
+ || (mode1 != BLKmode
+ && bitsize < GET_MODE_SIZE (mode1) * BITS_PER_UNIT)))
/* If the field isn't aligned enough to fetch as a memref,
fetch it as a bit field. */
|| (mode1 != BLKmode
if (ext_mode == BLKmode)
{
if (target == 0)
- target = assign_temp (type, 0, 1, 1);
+ target = assign_temp (type, 1, 1);
if (bitsize == 0)
return target;
necessarily be constant. */
if (mode == BLKmode)
{
- HOST_WIDE_INT size = GET_MODE_BITSIZE (ext_mode);
rtx new_rtx;
- /* If the reference doesn't use the alias set of its type,
- we cannot create the temporary using that type. */
- if (component_uses_parent_alias_set (exp))
- {
- new_rtx = assign_stack_local (ext_mode, size, 0);
- set_mem_alias_set (new_rtx, get_alias_set (exp));
- }
- else
- new_rtx = assign_stack_temp_for_type (ext_mode, size, 0, type);
-
+ new_rtx = assign_stack_temp_for_type (ext_mode,
+ GET_MODE_BITSIZE (ext_mode),
+ type);
emit_move_insn (new_rtx, op0);
op0 = copy_rtx (new_rtx);
PUT_MODE (op0, BLKmode);
- set_mem_attributes (op0, exp, 1);
}
return op0;
if (op0 == orig_op0)
op0 = copy_rtx (op0);
- set_mem_attributes (op0, exp, 0);
+ /* If op0 is a temporary because of forcing to memory, pass only the
+ type to set_mem_attributes so that the original expression is never
+ marked as ADDRESSABLE through MEM_EXPR of the temporary. */
+ if (mem_attrs_from_type)
+ set_mem_attributes (op0, type, 0);
+ else
+ set_mem_attributes (op0, exp, 0);
+
if (REG_P (XEXP (op0, 0)))
mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
target
= assign_stack_temp_for_type
(TYPE_MODE (inner_type),
- GET_MODE_SIZE (TYPE_MODE (inner_type)), 0, inner_type);
+ GET_MODE_SIZE (TYPE_MODE (inner_type)), inner_type);
emit_move_insn (target, op0);
op0 = target;
results. */
if (MEM_P (op0))
{
+ enum insn_code icode;
+
op0 = copy_rtx (op0);
if (TYPE_ALIGN_OK (type))
set_mem_align (op0, MAX (MEM_ALIGN (op0), TYPE_ALIGN (type)));
+ else if (mode != BLKmode
+ && MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode)
+ /* If the target does have special handling for unaligned
+ loads of mode then use them. */
+ && ((icode = optab_handler (movmisalign_optab, mode))
+ != CODE_FOR_nothing))
+ {
+ rtx reg, insn;
+
+ op0 = adjust_address (op0, mode, 0);
+ /* We've already validated the memory, and we're creating a
+ new pseudo destination. The predicates really can't
+ fail. */
+ reg = gen_reg_rtx (mode);
+
+ /* Nor can the insn generator. */
+ insn = GEN_FCN (icode) (reg, op0);
+ emit_insn (insn);
+ return reg;
+ }
else if (STRICT_ALIGNMENT
&& mode != BLKmode
&& MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode))
= MAX (int_size_in_bytes (inner_type),
(HOST_WIDE_INT) GET_MODE_SIZE (mode));
rtx new_rtx
- = assign_stack_temp_for_type (mode, temp_size, 0, type);
+ = assign_stack_temp_for_type (mode, temp_size, type);
rtx new_with_op0_mode
= adjust_address (new_rtx, GET_MODE (op0), 0);
case POSTDECREMENT_EXPR:
case LOOP_EXPR:
case EXIT_EXPR:
+ case COMPOUND_LITERAL_EXPR:
/* Lowered by gimplify.c. */
gcc_unreachable ();
return expand_expr_real (treeop0, original_target, tmode,
modifier, alt_rtl);
- case COMPOUND_LITERAL_EXPR:
- {
- /* Initialize the anonymous variable declared in the compound
- literal, then return the variable. */
- tree decl = COMPOUND_LITERAL_EXPR_DECL (exp);
-
- /* Create RTL for this variable. */
- if (!DECL_RTL_SET_P (decl))
- {
- if (DECL_HARD_REGISTER (decl))
- /* The user specified an assembler name for this variable.
- Set that up now. */
- rest_of_decl_compilation (decl, 0, 0);
- else
- expand_decl (decl);
- }
-
- return expand_expr_real (decl, original_target, tmode,
- modifier, alt_rtl);
- }
-
default:
return expand_expr_real_2 (&ops, target, tmode, modifier);
}
so we just call into the folder and expand its result. */
if ((code == NE || code == EQ)
- && TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1)
- && integer_pow2p (TREE_OPERAND (arg0, 1))
+ && integer_zerop (arg1)
&& (TYPE_PRECISION (ops->type) != 1 || TYPE_UNSIGNED (ops->type)))
{
- tree type = lang_hooks.types.type_for_mode (mode, unsignedp);
- return expand_expr (fold_single_bit_test (loc,
- code == NE ? NE_EXPR : EQ_EXPR,
- arg0, arg1, type),
- target, VOIDmode, EXPAND_NORMAL);
+ gimple srcstmt = get_def_for_expr (arg0, BIT_AND_EXPR);
+ if (srcstmt
+ && integer_pow2p (gimple_assign_rhs2 (srcstmt)))
+ {
+ enum tree_code tcode = code == NE ? NE_EXPR : EQ_EXPR;
+ tree type = lang_hooks.types.type_for_mode (mode, unsignedp);
+ tree temp = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (arg1),
+ gimple_assign_rhs1 (srcstmt),
+ gimple_assign_rhs2 (srcstmt));
+ temp = fold_single_bit_test (loc, tcode, temp, arg1, type);
+ if (temp)
+ return expand_expr (temp, target, VOIDmode, EXPAND_NORMAL);
+ }
}
if (! get_subtarget (target)
{
struct expand_operand ops[5];
enum machine_mode index_mode = SImode;
- int index_bits = GET_MODE_BITSIZE (index_mode);
rtx op1, op2, index;
if (! HAVE_casesi)
{
if (TYPE_MODE (index_type) != index_mode)
{
- index_type = lang_hooks.types.type_for_size (index_bits, 0);
+ index_type = lang_hooks.types.type_for_mode (index_mode, 0);
index_expr = fold_convert (index_type, index_expr);
}
const_vector_from_tree (tree exp)
{
rtvec v;
- int units, i;
- tree link, elt;
+ unsigned i;
+ int units;
+ tree elt;
enum machine_mode inner, mode;
mode = TYPE_MODE (TREE_TYPE (exp));
v = rtvec_alloc (units);
- link = TREE_VECTOR_CST_ELTS (exp);
- for (i = 0; link; link = TREE_CHAIN (link), ++i)
+ for (i = 0; i < VECTOR_CST_NELTS (exp); ++i)
{
- elt = TREE_VALUE (link);
+ elt = VECTOR_CST_ELT (exp, i);
if (TREE_CODE (elt) == REAL_CST)
RTVEC_ELT (v, i) = CONST_DOUBLE_FROM_REAL_VALUE (TREE_REAL_CST (elt),
inner);
}
- /* Initialize remaining elements to 0. */
- for (; i < units; ++i)
- RTVEC_ELT (v, i) = CONST0_RTX (inner);
-
return gen_rtx_CONST_VECTOR (mode, v);
}