/* 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,
- 2012 Free Software Foundation, Inc.
+ Copyright (C) 1988-2013 Free Software Foundation, Inc.
This file is part of GCC.
#include "intl.h"
#include "tm_p.h"
#include "tree-iterator.h"
-#include "tree-flow.h"
+#include "tree-ssa.h"
#include "target.h"
#include "common/common-target.h"
#include "timevar.h"
#include "df.h"
#include "diagnostic.h"
-#include "ssaexpand.h"
+#include "tree-outof-ssa.h"
#include "target-globals.h"
#include "params.h"
int reverse;
};
-static void move_by_pieces_1 (rtx (*) (rtx, ...), enum machine_mode,
+static void move_by_pieces_1 (insn_gen_fn, machine_mode,
struct move_by_pieces_d *);
static bool block_move_libcall_safe_for_call_parm (void);
static bool emit_block_move_via_movmem (rtx, rtx, rtx, unsigned, unsigned, HOST_WIDE_INT);
static rtx clear_by_pieces_1 (void *, HOST_WIDE_INT, enum machine_mode);
static void clear_by_pieces (rtx, unsigned HOST_WIDE_INT, unsigned int);
static void store_by_pieces_1 (struct store_by_pieces_d *, unsigned int);
-static void store_by_pieces_2 (rtx (*) (rtx, ...), enum machine_mode,
+static void store_by_pieces_2 (insn_gen_fn, machine_mode,
struct store_by_pieces_d *);
static tree clear_storage_libcall_fn (int);
static rtx compress_float_constant (rtx, rtx);
to make a move insn for that mode. DATA has all the other info. */
static void
-move_by_pieces_1 (rtx (*genfun) (rtx, ...), enum machine_mode mode,
+move_by_pieces_1 (insn_gen_fn genfun, machine_mode mode,
struct move_by_pieces_d *data)
{
unsigned int size = GET_MODE_SIZE (mode);
if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0)
emit_insn (gen_add2_insn (data->to_addr,
- GEN_INT (-(HOST_WIDE_INT)size)));
+ gen_int_mode (-(HOST_WIDE_INT) size,
+ GET_MODE (data->to_addr))));
if (HAVE_PRE_DECREMENT && data->explicit_inc_from < 0)
emit_insn (gen_add2_insn (data->from_addr,
- GEN_INT (-(HOST_WIDE_INT)size)));
+ gen_int_mode (-(HOST_WIDE_INT) size,
+ GET_MODE (data->from_addr))));
if (data->to)
emit_insn ((*genfun) (to1, from1));
}
if (HAVE_POST_INCREMENT && data->explicit_inc_to > 0)
- emit_insn (gen_add2_insn (data->to_addr, GEN_INT (size)));
+ emit_insn (gen_add2_insn (data->to_addr,
+ gen_int_mode (size,
+ GET_MODE (data->to_addr))));
if (HAVE_POST_INCREMENT && data->explicit_inc_from > 0)
- emit_insn (gen_add2_insn (data->from_addr, GEN_INT (size)));
+ emit_insn (gen_add2_insn (data->from_addr,
+ gen_int_mode (size,
+ GET_MODE (data->from_addr))));
if (! data->reverse)
data->offset += size;
emit_move_insn (orig_dst, dst);
}
+/* Return a form of X that does not use a PARALLEL. TYPE is the type
+ of the value stored in X. */
+
+rtx
+maybe_emit_group_store (rtx x, tree type)
+{
+ enum machine_mode mode = TYPE_MODE (type);
+ gcc_checking_assert (GET_MODE (x) == VOIDmode || GET_MODE (x) == mode);
+ if (GET_CODE (x) == PARALLEL)
+ {
+ rtx result = gen_reg_rtx (mode);
+ emit_group_store (result, x, type, int_size_in_bytes (type));
+ return result;
+ }
+ return x;
+}
+
/* Copy a BLKmode object of TYPE out of a register SRCREG into TARGET.
This is used on targets that return BLKmode values in registers. */
to make a move insn for that mode. DATA has all the other info. */
static void
-store_by_pieces_2 (rtx (*genfun) (rtx, ...), enum machine_mode mode,
+store_by_pieces_2 (insn_gen_fn genfun, machine_mode mode,
struct store_by_pieces_d *data)
{
unsigned int size = GET_MODE_SIZE (mode);
if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0)
emit_insn (gen_add2_insn (data->to_addr,
- GEN_INT (-(HOST_WIDE_INT) size)));
+ gen_int_mode (-(HOST_WIDE_INT) size,
+ GET_MODE (data->to_addr))));
cst = (*data->constfun) (data->constfundata, data->offset, mode);
emit_insn ((*genfun) (to1, cst));
if (HAVE_POST_INCREMENT && data->explicit_inc_to > 0)
- emit_insn (gen_add2_insn (data->to_addr, GEN_INT (size)));
+ emit_insn (gen_add2_insn (data->to_addr,
+ gen_int_mode (size,
+ GET_MODE (data->to_addr))));
if (! data->reverse)
data->offset += size;
/* Do not use anti_adjust_stack, since we don't want to update
stack_pointer_delta. */
temp = expand_simple_binop (Pmode, PLUS, stack_pointer_rtx,
- GEN_INT (adjust), stack_pointer_rtx,
+ gen_int_mode (adjust, Pmode), stack_pointer_rtx,
0, OPTAB_LIB_WIDEN);
if (temp != stack_pointer_rtx)
emit_move_insn (stack_pointer_rtx, temp);
if (push_operand (x, mode))
return emit_move_complex_push (mode, x, y);
- /* See if we can coerce the target into moving both values at once. */
-
- /* Move floating point as parts. */
+ /* See if we can coerce the target into moving both values at once, except
+ for floating point where we favor moving as parts if this is easy. */
if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
- && optab_handler (mov_optab, GET_MODE_INNER (mode)) != CODE_FOR_nothing)
+ && optab_handler (mov_optab, GET_MODE_INNER (mode)) != CODE_FOR_nothing
+ && !(REG_P (x)
+ && HARD_REGISTER_P (x)
+ && hard_regno_nregs[REGNO(x)][mode] == 1)
+ && !(REG_P (y)
+ && HARD_REGISTER_P (y)
+ && hard_regno_nregs[REGNO(y)][mode] == 1))
try_int = false;
/* Not possible if the values are inherently not adjacent. */
else if (GET_CODE (x) == CONCAT || GET_CODE (y) == CONCAT)
{
temp = copy_to_mode_reg (Pmode, size);
if (extra != 0)
- temp = expand_binop (Pmode, add_optab, temp, GEN_INT (extra),
+ temp = expand_binop (Pmode, add_optab, temp,
+ gen_int_mode (extra, Pmode),
temp, 0, OPTAB_LIB_WIDEN);
anti_adjust_stack (temp);
}
add_optab,
#endif
stack_pointer_rtx,
- GEN_INT (rounded_size),
+ gen_int_mode (rounded_size, Pmode),
NULL_RTX, 0, OPTAB_LIB_WIDEN));
offset = (HOST_WIDE_INT) padding_size;
previous value. */
offset -= (HOST_WIDE_INT) rounded_size;
#endif
- dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset));
+ dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+ gen_int_mode (offset, Pmode));
}
else
{
#ifdef STACK_GROWS_DOWNWARD
/* ??? This seems wrong if STACK_PUSH_CODE == POST_DEC. */
dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
- GEN_INT (-(HOST_WIDE_INT) rounded_size));
+ gen_int_mode (-(HOST_WIDE_INT) rounded_size,
+ Pmode));
#else
/* ??? This seems wrong if STACK_PUSH_CODE == POST_INC. */
dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
- GEN_INT (rounded_size));
+ gen_int_mode (rounded_size, Pmode));
#endif
dest_addr = gen_rtx_PRE_MODIFY (Pmode, stack_pointer_rtx, dest_addr);
}
size = GEN_INT (INTVAL (size) - used);
else
size = expand_binop (GET_MODE (size), sub_optab, size,
- GEN_INT (used), NULL_RTX, 0,
- OPTAB_LIB_WIDEN);
+ gen_int_mode (used, GET_MODE (size)),
+ NULL_RTX, 0, OPTAB_LIB_WIDEN);
}
/* Get the address of the stack space.
binop = code == BIT_IOR_EXPR ? ior_optab : xor_optab;
if (bitpos + bitsize != str_bitsize)
{
- rtx mask = GEN_INT (((unsigned HOST_WIDE_INT) 1 << bitsize) - 1);
+ rtx mask = gen_int_mode (((unsigned HOST_WIDE_INT) 1 << bitsize) - 1,
+ str_mode);
value = expand_and (str_mode, value, mask, NULL_RTX);
}
value = expand_shift (LSHIFT_EXPR, str_mode, value, bitpos, NULL_RTX, 1);
*bitend = *bitstart + tree_low_cst (DECL_SIZE (repr), 1) - 1;
}
+/* Returns true if ADDR is an ADDR_EXPR of a DECL that does not reside
+ in memory and has non-BLKmode. DECL_RTL must not be a MEM; if
+ DECL_RTL was not set yet, return NORTL. */
+
+static inline bool
+addr_expr_of_non_mem_decl_p_1 (tree addr, bool nortl)
+{
+ if (TREE_CODE (addr) != ADDR_EXPR)
+ return false;
+
+ tree base = TREE_OPERAND (addr, 0);
+
+ if (!DECL_P (base)
+ || TREE_ADDRESSABLE (base)
+ || DECL_MODE (base) == BLKmode)
+ return false;
+
+ if (!DECL_RTL_SET_P (base))
+ return nortl;
+
+ return (!MEM_P (DECL_RTL (base)));
+}
+
/* Returns true if the MEM_REF REF refers to an object that does not
reside in memory and has non-BLKmode. */
-static bool
+static inline 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)));
+ return addr_expr_of_non_mem_decl_p_1 (base, false);
+}
+
+/* Return TRUE iff OP is an ADDR_EXPR of a DECL that's not
+ addressable. This is very much like mem_ref_refers_to_non_mem_p,
+ but instead of the MEM_REF, it takes its base, and it doesn't
+ assume a DECL is in memory just because its RTL is not set yet. */
+
+bool
+addr_expr_of_non_mem_decl_p (tree op)
+{
+ return addr_expr_of_non_mem_decl_p_1 (op, true);
}
/* Expand an assignment that stores the value of FROM into TO. If NONTEMPORAL
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,
&& DECL_BIT_FIELD_TYPE (TREE_OPERAND (to, 1)))
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_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);
-
- mem = copy_rtx (mem);
- }
- }
- else
- {
- misalignp = false;
- to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_WRITE);
- }
+ 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.
/* If the field is at offset zero, we could have been given the
DECL_RTX of the parent struct. Don't munge it. */
to_rtx = shallow_copy_rtx (to_rtx);
-
set_mem_attributes_minus_bitpos (to_rtx, to, 0, bitpos);
-
- /* Deal with volatile and readonly fields. The former is only
- done for MEM. Also set MEM_KEEP_ALIAS_SET_P if needed. */
if (volatilep)
MEM_VOLATILE_P (to_rtx) = 1;
- if (component_uses_parent_alias_set (to))
- MEM_KEEP_ALIAS_SET_P (to_rtx) = 1;
}
if (optimize_bitfield_assignment_op (bitsize, bitpos,
get_alias_set (to), 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);
pop_temp_slots ();
rtx temp;
push_temp_slots ();
- if (REG_P (to_rtx) && TYPE_MODE (TREE_TYPE (from)) == BLKmode)
+
+ /* If the source is itself a return value, it still is in a pseudo at
+ this point so we can move it back to the return register directly. */
+ if (REG_P (to_rtx)
+ && TYPE_MODE (TREE_TYPE (from)) == BLKmode
+ && TREE_CODE (from) != CALL_EXPR)
temp = copy_blkmode_to_reg (GET_MODE (to_rtx), from);
else
temp = expand_expr (from, NULL_RTX, GET_MODE (to_rtx), EXPAND_NORMAL);
if (!integer_zerop (off))
{
double_int boff, coff = mem_ref_offset (exp);
- boff = coff.alshift (BITS_PER_UNIT == 8
- ? 3 : exact_log2 (BITS_PER_UNIT),
- HOST_BITS_PER_DOUBLE_INT);
+ boff = coff.lshift (BITS_PER_UNIT == 8
+ ? 3 : exact_log2 (BITS_PER_UNIT));
bit_offset += boff;
}
exp = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
{
double_int tem = tree_to_double_int (offset);
tem = tem.sext (TYPE_PRECISION (sizetype));
- tem = tem.alshift (BITS_PER_UNIT == 8 ? 3 : exact_log2 (BITS_PER_UNIT),
- HOST_BITS_PER_DOUBLE_INT);
+ tem = tem.lshift (BITS_PER_UNIT == 8 ? 3 : exact_log2 (BITS_PER_UNIT));
tem += bit_offset;
if (tem.fits_shwi ())
{
inner = TREE_OPERAND (exp, 0);
break;
+ case COMPOUND_LITERAL_EXPR:
+ /* Allow COMPOUND_LITERAL_EXPR in initializers, if e.g.
+ rtl_for_decl_init is called on DECL_INITIAL with
+ COMPOUNT_LITERAL_EXPRs in it, they aren't gimplified. */
+ if (modifier == EXPAND_INITIALIZER
+ && COMPOUND_LITERAL_EXPR_DECL (exp))
+ return expand_expr_addr_expr_1 (COMPOUND_LITERAL_EXPR_DECL (exp),
+ target, tmode, modifier, as);
+ /* FALLTHRU */
default:
/* If the object is a DECL, then expand it for its rtl. Don't bypass
expand_expr, as that can have various side effects; LABEL_DECLs for
tree type = TREE_TYPE (treeop1);
int unsignedp = TYPE_UNSIGNED (type);
enum machine_mode mode = TYPE_MODE (type);
+ enum machine_mode orig_mode = mode;
/* If we cannot do a conditional move on the mode, try doing it
with the promoted mode. */
rtx seq = get_insns ();
end_sequence ();
emit_insn (seq);
- return temp;
+ return convert_modes (orig_mode, mode, temp, 0);
}
/* Otherwise discard the sequence and fall back to code with
else
expand_operands (treeop0, treeop1, NULL_RTX, &op1, &op0,
EXPAND_NORMAL);
+ /* op0 and op1 might still be constant, despite the above
+ != INTEGER_CST check. Handle it. */
+ if (GET_MODE (op0) == VOIDmode && GET_MODE (op1) == VOIDmode)
+ {
+ op0 = convert_modes (innermode, mode, op0, true);
+ op1 = convert_modes (innermode, mode, op1, false);
+ return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1,
+ target, unsignedp));
+ }
goto binop3;
}
}
{
expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1,
EXPAND_NORMAL);
+ /* op0 and op1 might still be constant, despite the above
+ != INTEGER_CST check. Handle it. */
+ if (GET_MODE (op0) == VOIDmode && GET_MODE (op1) == VOIDmode)
+ {
+ widen_mult_const:
+ op0 = convert_modes (innermode, mode, op0, zextend_p);
+ op1
+ = convert_modes (innermode, mode, op1,
+ TYPE_UNSIGNED (TREE_TYPE (treeop1)));
+ return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1,
+ target,
+ unsignedp));
+ }
temp = expand_widening_mult (mode, op0, op1, target,
unsignedp, this_optab);
return REDUCE_BIT_FIELD (temp);
op0 = expand_normal (treeop0);
if (TREE_CODE (treeop1) == INTEGER_CST)
op1 = convert_modes (innermode, mode,
- expand_normal (treeop1), unsignedp);
+ expand_normal (treeop1),
+ TYPE_UNSIGNED (TREE_TYPE (treeop1)));
else
op1 = expand_normal (treeop1);
+ /* op0 and op1 might still be constant, despite the above
+ != INTEGER_CST check. Handle it. */
+ if (GET_MODE (op0) == VOIDmode && GET_MODE (op1) == VOIDmode)
+ goto widen_mult_const;
temp = expand_binop (mode, other_optab, op0, op1, target,
unsignedp, OPTAB_LIB_WIDEN);
hipart = gen_highpart (innermode, temp);
if (!target)
target = gen_reg_rtx (TYPE_MODE (type));
+ else
+ /* If target overlaps with op1, then either we need to force
+ op1 into a pseudo (if target also overlaps with op0),
+ or write the complex parts in reverse order. */
+ switch (GET_CODE (target))
+ {
+ case CONCAT:
+ if (reg_overlap_mentioned_p (XEXP (target, 0), op1))
+ {
+ if (reg_overlap_mentioned_p (XEXP (target, 1), op0))
+ {
+ complex_expr_force_op1:
+ temp = gen_reg_rtx (GET_MODE_INNER (GET_MODE (target)));
+ emit_move_insn (temp, op1);
+ op1 = temp;
+ break;
+ }
+ complex_expr_swap_order:
+ /* Move the imaginary (op1) and real (op0) parts to their
+ location. */
+ write_complex_part (target, op1, true);
+ write_complex_part (target, op0, false);
+
+ return target;
+ }
+ break;
+ case MEM:
+ temp = adjust_address_nv (target,
+ GET_MODE_INNER (GET_MODE (target)), 0);
+ if (reg_overlap_mentioned_p (temp, op1))
+ {
+ enum machine_mode imode = GET_MODE_INNER (GET_MODE (target));
+ temp = adjust_address_nv (target, imode,
+ GET_MODE_SIZE (imode));
+ if (reg_overlap_mentioned_p (temp, op0))
+ goto complex_expr_force_op1;
+ goto complex_expr_swap_order;
+ }
+ break;
+ default:
+ if (reg_overlap_mentioned_p (target, op1))
+ {
+ if (reg_overlap_mentioned_p (target, op0))
+ goto complex_expr_force_op1;
+ goto complex_expr_swap_order;
+ }
+ break;
+ }
/* Move the real (op0) and imaginary (op1) parts to their location. */
write_complex_part (target, op0, false);
}
#undef REDUCE_BIT_FIELD
+
+/* Return TRUE if expression STMT is suitable for replacement.
+ Never consider memory loads as replaceable, because those don't ever lead
+ into constant expressions. */
+
+static bool
+stmt_is_replaceable_p (gimple stmt)
+{
+ if (ssa_is_replaceable_p (stmt))
+ {
+ /* Don't move around loads. */
+ if (!gimple_assign_single_p (stmt)
+ || is_gimple_val (gimple_assign_rhs1 (stmt)))
+ return true;
+ }
+ return false;
+}
+
rtx
expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
enum expand_modifier modifier, rtx *alt_rtl)
/* Variables inherited from containing functions should have
been lowered by this point. */
context = decl_function_context (exp);
- gcc_assert (!context
+ gcc_assert (SCOPE_FILE_SCOPE_P (context)
|| context == current_function_decl
|| TREE_STATIC (exp)
|| DECL_EXTERNAL (exp)
set_mem_addr_space (temp, as);
align = get_object_alignment (exp);
if (modifier != EXPAND_WRITE
+ && modifier != EXPAND_MEMORY
&& mode != BLKmode
&& align < GET_MODE_ALIGNMENT (mode)
/* If the target does not have special handling for unaligned
create_output_operand (&ops[0], NULL_RTX, mode);
create_fixed_operand (&ops[1], temp);
expand_insn (icode, 2, ops);
- return ops[0].value;
+ temp = ops[0].value;
}
return temp;
}
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 (offset == 0
- && host_integerp (TYPE_SIZE (TREE_TYPE (exp)), 1)
+ && host_integerp (TYPE_SIZE (type), 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),
+ == TREE_INT_CST_LOW (TYPE_SIZE (type))))
+ return expand_expr (build1 (VIEW_CONVERT_EXPR, type, 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
+ if (TYPE_MODE (type) == BLKmode)
{
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)));
+ set_mem_size (temp, int_size_in_bytes (type));
return temp;
}
- return expand_expr (build3 (BIT_FIELD_REF, bftype,
- base,
- TYPE_SIZE (TREE_TYPE (exp)),
- bit_offset),
- target, tmode, modifier);
+ exp = build3 (BIT_FIELD_REF, type, base, TYPE_SIZE (type),
+ bitsize_int (offset * BITS_PER_UNIT));
+ return expand_expr (exp, target, tmode, modifier);
}
address_mode = targetm.addr_space.address_mode (as);
base = TREE_OPERAND (exp, 0);
if (TREE_THIS_VOLATILE (exp))
MEM_VOLATILE_P (temp) = 1;
if (modifier != EXPAND_WRITE
+ && modifier != EXPAND_MEMORY
&& mode != BLKmode
&& align < GET_MODE_ALIGNMENT (mode))
{
create_output_operand (&ops[0], NULL_RTX, mode);
create_fixed_operand (&ops[1], temp);
expand_insn (icode, 2, ops);
- return ops[0].value;
+ temp = ops[0].value;
}
else if (SLOW_UNALIGNED_ACCESS (mode, align))
temp = extract_bit_field (temp, GET_MODE_BITSIZE (mode),
{
tree array = treeop0;
tree index = treeop1;
+ tree init;
/* Fold an expression like: "foo"[2].
This is not done in fold so it won't happen inside &.
&& modifier != EXPAND_INITIALIZER
&& modifier != EXPAND_MEMORY
&& TREE_READONLY (array) && ! TREE_SIDE_EFFECTS (array)
- && TREE_CODE (array) == VAR_DECL && DECL_INITIAL (array)
- && TREE_CODE (DECL_INITIAL (array)) != ERROR_MARK
- && const_value_known_p (array))
+ && TREE_CODE (index) == INTEGER_CST
+ && (TREE_CODE (array) == VAR_DECL
+ || TREE_CODE (array) == CONST_DECL)
+ && (init = ctor_for_folding (array)) != error_mark_node)
{
- if (TREE_CODE (index) == INTEGER_CST)
+ if (TREE_CODE (init) == CONSTRUCTOR)
{
- tree init = DECL_INITIAL (array);
-
- if (TREE_CODE (init) == CONSTRUCTOR)
- {
- unsigned HOST_WIDE_INT ix;
- tree field, value;
+ unsigned HOST_WIDE_INT ix;
+ tree field, value;
+
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), ix,
+ field, value)
+ if (tree_int_cst_equal (field, index))
+ {
+ if (TREE_SIDE_EFFECTS (value))
+ break;
- FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), ix,
- field, value)
- if (tree_int_cst_equal (field, index))
+ if (TREE_CODE (value) == CONSTRUCTOR)
{
- if (TREE_SIDE_EFFECTS (value))
+ /* If VALUE is a CONSTRUCTOR, this
+ optimization is only useful if
+ this doesn't store the CONSTRUCTOR
+ into memory. If it does, it is more
+ efficient to just load the data from
+ the array directly. */
+ rtx ret = expand_constructor (value, target,
+ modifier, true);
+ if (ret == NULL_RTX)
break;
-
- if (TREE_CODE (value) == CONSTRUCTOR)
- {
- /* If VALUE is a CONSTRUCTOR, this
- optimization is only useful if
- this doesn't store the CONSTRUCTOR
- into memory. If it does, it is more
- efficient to just load the data from
- the array directly. */
- rtx ret = expand_constructor (value, target,
- modifier, true);
- if (ret == NULL_RTX)
- break;
- }
-
- return expand_expr (fold (value), target, tmode,
- modifier);
}
- }
- else if(TREE_CODE (init) == STRING_CST)
- {
- tree index1 = index;
- tree low_bound = array_ref_low_bound (exp);
- index1 = fold_convert_loc (loc, sizetype,
- treeop1);
-
- /* Optimize the special-case of a zero lower bound.
-
- We convert the low_bound to sizetype to avoid some problems
- with constant folding. (E.g. suppose the lower bound is 1,
- and its mode is QI. Without the conversion,l (ARRAY
- +(INDEX-(unsigned char)1)) becomes ((ARRAY+(-(unsigned char)1))
- +INDEX), which becomes (ARRAY+255+INDEX). Opps!) */
- if (! integer_zerop (low_bound))
- index1 = size_diffop_loc (loc, index1,
+ return
+ expand_expr (fold (value), target, tmode, modifier);
+ }
+ }
+ else if (TREE_CODE (init) == STRING_CST)
+ {
+ tree low_bound = array_ref_low_bound (exp);
+ tree index1 = fold_convert_loc (loc, sizetype, treeop1);
+
+ /* Optimize the special case of a zero lower bound.
+
+ We convert the lower bound to sizetype to avoid problems
+ with constant folding. E.g. suppose the lower bound is
+ 1 and its mode is QI. Without the conversion
+ (ARRAY + (INDEX - (unsigned char)1))
+ becomes
+ (ARRAY + (-(unsigned char)1) + INDEX)
+ which becomes
+ (ARRAY + 255 + INDEX). Oops! */
+ if (!integer_zerop (low_bound))
+ index1 = size_diffop_loc (loc, index1,
fold_convert_loc (loc, sizetype,
low_bound));
- if (0 > compare_tree_int (index1,
- TREE_STRING_LENGTH (init)))
- {
- tree type = TREE_TYPE (TREE_TYPE (init));
- enum machine_mode mode = TYPE_MODE (type);
-
- if (GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_SIZE (mode) == 1)
- return gen_int_mode (TREE_STRING_POINTER (init)
- [TREE_INT_CST_LOW (index1)],
- mode);
- }
+ if (compare_tree_int (index1, TREE_STRING_LENGTH (init)) < 0)
+ {
+ tree type = TREE_TYPE (TREE_TYPE (init));
+ enum machine_mode mode = TYPE_MODE (type);
+
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && GET_MODE_SIZE (mode) == 1)
+ return gen_int_mode (TREE_STRING_POINTER (init)
+ [TREE_INT_CST_LOW (index1)],
+ mode);
}
}
}
if (TYPE_UNSIGNED (TREE_TYPE (field)))
{
- op1 = GEN_INT (((HOST_WIDE_INT) 1 << bitsize) - 1);
+ op1 = gen_int_mode (((HOST_WIDE_INT) 1 << bitsize) - 1,
+ imode);
op0 = expand_and (imode, op0, op1, target);
}
else
&& modifier != EXPAND_STACK_PARM
? target : NULL_RTX),
VOIDmode,
- (modifier == EXPAND_INITIALIZER
- || modifier == EXPAND_CONST_ADDRESS
- || modifier == EXPAND_STACK_PARM)
- ? modifier : EXPAND_NORMAL);
-
+ modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier);
/* If the bitfield is volatile, we want to access it in the
field's mode, not the computed mode.
&& GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
&& GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT
&& modifier != EXPAND_CONST_ADDRESS
- && modifier != EXPAND_INITIALIZER)
+ && modifier != EXPAND_INITIALIZER
+ && modifier != EXPAND_MEMORY)
/* If the field is volatile, we always want an aligned
access. Do this in following two situations:
1. the access is not already naturally
|| (MEM_P (op0)
&& (MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode1)
|| (bitpos % GET_MODE_ALIGNMENT (mode1) != 0))))
+ && modifier != EXPAND_MEMORY
&& ((modifier == EXPAND_CONST_ADDRESS
|| modifier == EXPAND_INITIALIZER)
? STRICT_ALIGNMENT
|| modifier == EXPAND_CONST_ADDRESS
|| modifier == EXPAND_INITIALIZER)
return op0;
- else if (target == 0)
+
+ if (target == 0)
target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
convert_move (target, op0, unsignedp);
/* If we are converting to BLKmode, try to avoid an intermediate
temporary by fetching an inner memory reference. */
if (mode == BLKmode
- && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) == INTEGER_CST
+ && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
&& TYPE_MODE (TREE_TYPE (treeop0)) != BLKmode
&& handled_component_p (treeop0))
{
if (!offset
&& (bitpos % BITS_PER_UNIT) == 0
&& bitsize >= 0
- && compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) == 0)
+ && compare_tree_int (TYPE_SIZE (type), bitsize) == 0)
{
/* See the normal_inner_ref case for the rationale. */
orig_op0
&& modifier != EXPAND_STACK_PARM
? target : NULL_RTX),
VOIDmode,
- (modifier == EXPAND_INITIALIZER
- || modifier == EXPAND_CONST_ADDRESS
- || modifier == EXPAND_STACK_PARM)
- ? modifier : EXPAND_NORMAL);
+ modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier);
if (MEM_P (orig_op0))
{
}
if (!op0)
- op0 = expand_expr (treeop0,
- NULL_RTX, VOIDmode, modifier);
+ op0 = expand_expr (treeop0, NULL_RTX, VOIDmode, modifier);
/* If the input and output modes are both the same, we are done. */
if (mode == GET_MODE (op0))
|| TREE_CODE (array) == CONST_DECL)
{
int length;
+ tree init = ctor_for_folding (array);
/* Variables initialized to string literals can be handled too. */
- if (!const_value_known_p (array)
- || !DECL_INITIAL (array)
- || TREE_CODE (DECL_INITIAL (array)) != STRING_CST)
+ if (init == error_mark_node
+ || !init
+ || TREE_CODE (init) != STRING_CST)
return 0;
/* Avoid const char foo[4] = "abcde"; */
if (DECL_SIZE_UNIT (array) == NULL_TREE
|| TREE_CODE (DECL_SIZE_UNIT (array)) != INTEGER_CST
- || (length = TREE_STRING_LENGTH (DECL_INITIAL (array))) <= 0
+ || (length = TREE_STRING_LENGTH (init)) <= 0
|| compare_tree_int (DECL_SIZE_UNIT (array), length) < 0)
return 0;
return 0;
*ptr_offset = offset;
- return DECL_INITIAL (array);
+ return init;
}
return 0;
GET_MODE_SIZE, because this indicates how large insns are. The other
uses should all be Pmode, because they are addresses. This code
could fail if addresses and insns are not the same size. */
- index = gen_rtx_PLUS (Pmode,
- gen_rtx_MULT (Pmode, index,
- GEN_INT (GET_MODE_SIZE (CASE_VECTOR_MODE))),
- gen_rtx_LABEL_REF (Pmode, table_label));
+ index = gen_rtx_PLUS
+ (Pmode,
+ gen_rtx_MULT (Pmode, index,
+ gen_int_mode (GET_MODE_SIZE (CASE_VECTOR_MODE), Pmode)),
+ gen_rtx_LABEL_REF (Pmode, table_label));
#ifdef PIC_CASE_VECTOR_ADDRESS
if (flag_pic)
index = PIC_CASE_VECTOR_ADDRESS (index);