#include "tree-flow.h"
#include "target.h"
#include "timevar.h"
+#include "df.h"
/* Decide whether a function's arguments should be processed
from first to last or from last to first.
tree, tree, int, int);
static void store_constructor (tree, rtx, int, HOST_WIDE_INT);
static rtx store_field (rtx, HOST_WIDE_INT, HOST_WIDE_INT, enum machine_mode,
- tree, tree, int);
+ tree, tree, int, bool);
static unsigned HOST_WIDE_INT highest_pow2_factor_for_target (tree, tree);
if (! HARD_REGNO_MODE_OK (regno, mode))
continue;
- REGNO (reg) = regno;
+ SET_REGNO (reg, regno);
SET_SRC (pat) = mem;
SET_DEST (pat) = reg;
gcc_assert (to_real == from_real);
+ gcc_assert (to_mode != BLKmode);
+ gcc_assert (from_mode != BLKmode);
/* If the source and destination are already the same, then there's
nothing to do. */
!= GET_MODE_PRECISION (to_mode))
|| (DECIMAL_FLOAT_MODE_P (from_mode)
!= DECIMAL_FLOAT_MODE_P (to_mode)));
-
+
if (GET_MODE_PRECISION (from_mode) == GET_MODE_PRECISION (to_mode))
/* Conversion between decimal float and binary float, same size. */
tab = DECIMAL_FLOAT_MODE_P (from_mode) ? trunc_optab : sext_optab;
use_reg (rtx *call_fusage, rtx reg)
{
gcc_assert (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER);
-
+
*call_fusage
= gen_rtx_EXPR_LIST (VOIDmode,
gen_rtx_USE (VOIDmode, reg), *call_fusage);
pred = insn_data[(int) code].operand[1].predicate;
if (pred != 0 && ! (*pred) (opsize, mode))
opsize = copy_to_mode_reg (mode, opsize);
-
+
opchar = val;
char_mode = insn_data[(int) code].operand[2].mode;
if (char_mode != VOIDmode)
{
rtx ret;
- if (MEM_P (x))
+ if (push_operand (x, GET_MODE (x)))
+ {
+ ret = gen_rtx_MEM (new_mode, XEXP (x, 0));
+ MEM_COPY_ATTRIBUTES (ret, x);
+ }
+ else if (MEM_P (x))
{
/* We don't have to worry about changing the address since the
size in bytes is supposed to be the same. */
rtx seq, inner;
bool need_clobber;
int i;
-
+
gcc_assert (GET_MODE_SIZE (mode) >= UNITS_PER_WORD);
-
+
/* If X is a push on the stack, do the push now and replace
X with a reference to the stack pointer. */
if (push_operand (x, mode))
&& (bitsize != 1 || TREE_CODE (op1) != INTEGER_CST))
break;
- value = expand_expr (op1, NULL_RTX, str_mode, 0);
+ 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)));
case BIT_XOR_EXPR:
if (TREE_CODE (op1) != INTEGER_CST)
break;
- value = expand_expr (op1, NULL_RTX, GET_MODE (str_rtx), 0);
+ value = expand_expr (op1, NULL_RTX, GET_MODE (str_rtx), EXPAND_NORMAL);
value = convert_modes (GET_MODE (str_rtx),
TYPE_MODE (TREE_TYPE (op1)), value,
TYPE_UNSIGNED (TREE_TYPE (op1)));
}
-/* Expand an assignment that stores the value of FROM into TO. */
+/* Expand an assignment that stores the value of FROM into TO. If NONTEMPORAL
+ is true, try generating a nontemporal store. */
void
-expand_assignment (tree to, tree from)
+expand_assignment (tree to, tree from, bool nontemporal)
{
rtx to_rtx = 0;
rtx result;
if (TREE_CODE (TREE_TYPE (from)) == COMPLEX_TYPE)
{
gcc_assert (bitpos == 0);
- result = store_expr (from, to_rtx, false);
+ result = store_expr (from, to_rtx, false, nontemporal);
}
else
{
gcc_assert (bitpos == 0 || bitpos == GET_MODE_BITSIZE (mode1));
- result = store_expr (from, XEXP (to_rtx, bitpos != 0), false);
+ result = store_expr (from, XEXP (to_rtx, bitpos != 0), false,
+ nontemporal);
}
}
else
result = NULL;
else
result = store_field (to_rtx, bitsize, bitpos, mode1, from,
- TREE_TYPE (tem), get_alias_set (to));
+ TREE_TYPE (tem), get_alias_set (to),
+ nontemporal);
}
if (result)
rtx temp;
push_temp_slots ();
- temp = expand_expr (from, 0, GET_MODE (to_rtx), 0);
+ 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),
/* Compute FROM and store the value in the rtx we got. */
push_temp_slots ();
- result = store_expr (from, to_rtx, 0);
+ result = store_expr (from, to_rtx, 0, nontemporal);
preserve_temp_slots (result);
free_temp_slots ();
pop_temp_slots ();
return;
}
+/* Emits nontemporal store insn that moves FROM to TO. Returns true if this
+ succeeded, false otherwise. */
+
+static bool
+emit_storent_insn (rtx to, rtx from)
+{
+ enum machine_mode mode = GET_MODE (to), imode;
+ enum insn_code code = storent_optab->handlers[mode].insn_code;
+ rtx pattern;
+
+ if (code == CODE_FOR_nothing)
+ return false;
+
+ imode = insn_data[code].operand[0].mode;
+ if (!insn_data[code].operand[0].predicate (to, imode))
+ return false;
+
+ imode = insn_data[code].operand[1].mode;
+ if (!insn_data[code].operand[1].predicate (from, imode))
+ {
+ from = copy_to_mode_reg (imode, from);
+ if (!insn_data[code].operand[1].predicate (from, imode))
+ return false;
+ }
+
+ pattern = GEN_FCN (code) (to, from);
+ if (pattern == NULL_RTX)
+ return false;
+
+ emit_insn (pattern);
+ return true;
+}
+
/* Generate code for computing expression EXP,
and storing the value into TARGET.
be more thorough?
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. */
+ stack, and block moves may need to be treated specially.
+
+ If NONTEMPORAL is true, try using a nontemporal store instruction. */
rtx
-store_expr (tree exp, rtx target, int call_param_p)
+store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
{
rtx temp;
rtx alt_rtl = NULL_RTX;
branch and an rvalue in the other. Here, we resolve attempts to
store the throw expression's nonexistent result. */
gcc_assert (!call_param_p);
- expand_expr (exp, const0_rtx, VOIDmode, 0);
+ expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
return NULL_RTX;
}
if (TREE_CODE (exp) == COMPOUND_EXPR)
part. */
expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
call_param_p ? EXPAND_STACK_PARM : EXPAND_NORMAL);
- return store_expr (TREE_OPERAND (exp, 1), target, call_param_p);
+ return store_expr (TREE_OPERAND (exp, 1), target, call_param_p,
+ nontemporal);
}
else if (TREE_CODE (exp) == COND_EXPR && GET_MODE (target) == BLKmode)
{
do_pending_stack_adjust ();
NO_DEFER_POP;
jumpifnot (TREE_OPERAND (exp, 0), lab1);
- store_expr (TREE_OPERAND (exp, 1), target, call_param_p);
+ store_expr (TREE_OPERAND (exp, 1), target, call_param_p,
+ nontemporal);
emit_jump_insn (gen_jump (lab2));
emit_barrier ();
emit_label (lab1);
- store_expr (TREE_OPERAND (exp, 2), target, call_param_p);
+ store_expr (TREE_OPERAND (exp, 2), target, call_param_p,
+ nontemporal);
emit_label (lab2);
OK_DEFER_POP;
/* Some types, e.g. Fortran's logical*4, won't have a signed
version, so use the mode instead. */
tree ntype
- = (get_signed_or_unsigned_type
+ = (signed_or_unsigned_type_for
(SUBREG_PROMOTED_UNSIGNED_P (target), TREE_TYPE (exp)));
if (ntype == NULL)
ntype = lang_hooks.types.type_for_mode
}
else
{
- temp = expand_expr_real (exp, target, GET_MODE (target),
+ rtx tmp_target;
+
+ /* If we want to use a nontemporal store, force the value to
+ register first. */
+ tmp_target = nontemporal ? NULL_RTX : target;
+ temp = expand_expr_real (exp, tmp_target, GET_MODE (target),
(call_param_p
? EXPAND_STACK_PARM : EXPAND_NORMAL),
&alt_rtl);
temp = convert_to_mode (GET_MODE (target), temp, unsignedp);
emit_move_insn (target, temp);
}
+ else if (GET_MODE (target) == BLKmode)
+ emit_block_move (target, temp, expr_size (exp),
+ (call_param_p
+ ? BLOCK_OP_CALL_PARM
+ : BLOCK_OP_NORMAL));
else
convert_move (target, temp, unsignedp);
}
emit_block_move (target, temp, expr_size (exp),
(call_param_p
? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
+ else if (nontemporal
+ && emit_storent_insn (target, temp))
+ /* If we managed to emit a nontemporal store, there is nothing else to
+ do. */
+ ;
else
{
temp = force_operand (temp, target);
case CONSTRUCTOR:
{
HOST_WIDE_INT nz = 0, ic = 0;
-
+
bool const_elt_p
= categorize_ctor_elements_1 (value, &nz, &ic, p_must_clear);
largest element. Which would avoid comparing the size of the
initialized element against any tail padding in the union.
Doesn't seem worth the effort... */
- if (simple_cst_equal (TYPE_SIZE (TREE_TYPE (ctor)),
+ if (simple_cst_equal (TYPE_SIZE (TREE_TYPE (ctor)),
TYPE_SIZE (init_sub_type)) == 1)
{
/* And now we have to find out if the element itself is fully
store_constructor (exp, target, cleared, bitsize / BITS_PER_UNIT);
}
else
- store_field (target, bitsize, bitpos, mode, exp, type, alias_set);
+ store_field (target, bitsize, bitpos, mode, exp, type, alias_set, false);
}
/* Store the value of constructor EXP into the rtx TARGET.
cleared = 1;
}
- if (! cleared)
+ if (REG_P (target) && !cleared)
emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
/* Store each element of the constructor into the
HOST_WIDE_INT bitpos = 0;
tree offset;
rtx to_rtx = target;
-
+
/* Just ignore missing fields. We cleared the whole
structure, above, if any fields are missing. */
if (field == 0)
continue;
-
+
if (cleared && initializer_zerop (value))
continue;
-
+
if (host_integerp (DECL_SIZE (field), 1))
bitsize = tree_low_cst (DECL_SIZE (field), 1);
else
bitsize = -1;
-
+
mode = DECL_MODE (field);
if (DECL_BIT_FIELD (field))
mode = VOIDmode;
-
+
offset = DECL_FIELD_OFFSET (field);
if (host_integerp (offset, 0)
&& host_integerp (bit_position (field), 0))
}
else
bitpos = tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 0);
-
+
if (offset)
{
rtx offset_rtx;
-
+
offset
= SUBSTITUTE_PLACEHOLDER_IN_EXPR (offset,
make_tree (TREE_TYPE (exp),
offset_rtx = expand_normal (offset);
gcc_assert (MEM_P (to_rtx));
-
+
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (offset_rtx) != Pmode)
offset_rtx = convert_to_mode (Pmode, offset_rtx, 0);
&& bitpos + BITS_PER_WORD <= exp_size * BITS_PER_UNIT)
{
tree type = TREE_TYPE (value);
-
+
if (TYPE_PRECISION (type) < BITS_PER_WORD)
{
type = lang_hooks.types.type_for_size
(BITS_PER_WORD, TYPE_UNSIGNED (type));
value = fold_convert (type, value);
}
-
+
if (BYTES_BIG_ENDIAN)
value
= fold_build2 (LSHIFT_EXPR, type, value,
to_rtx = copy_rtx (to_rtx);
MEM_KEEP_ALIAS_SET_P (to_rtx) = 1;
}
-
+
store_constructor_field (to_rtx, bitsize, bitpos, mode,
value, type, cleared,
get_alias_set (TREE_TYPE (field)));
tree index, value;
HOST_WIDE_INT count = 0, zero_count = 0;
need_to_clear = ! const_bounds_p;
-
+
/* This loop is a more accurate version of the loop in
mostly_zeros_p (it handles RANGE_EXPR in an index). It
is also needed to check for missing elements. */
if (need_to_clear)
break;
-
+
if (index != NULL_TREE && TREE_CODE (index) == RANGE_EXPR)
{
tree lo_index = TREE_OPERAND (index, 0);
tree hi_index = TREE_OPERAND (index, 1);
-
+
if (! host_integerp (lo_index, 1)
|| ! host_integerp (hi_index, 1))
{
need_to_clear = 1;
break;
}
-
+
this_node_count = (tree_low_cst (hi_index, 1)
- tree_low_cst (lo_index, 1) + 1);
}
else
this_node_count = 1;
-
+
count += this_node_count;
if (mostly_zeros_p (value))
zero_count += this_node_count;
}
-
+
/* Clear the entire array first if there are any missing
elements, or if the incidence of zero elements is >=
75%. */
|| 4 * zero_count >= 3 * count))
need_to_clear = 1;
}
-
+
if (need_to_clear && size > 0)
{
if (REG_P (target))
HOST_WIDE_INT bitpos;
int unsignedp;
rtx xtarget = target;
-
+
if (cleared && initializer_zerop (value))
continue;
-
+
unsignedp = TYPE_UNSIGNED (elttype);
mode = TYPE_MODE (elttype);
if (mode == BLKmode)
: -1);
else
bitsize = GET_MODE_BITSIZE (mode);
-
+
if (index != NULL_TREE && TREE_CODE (index) == RANGE_EXPR)
{
tree lo_index = TREE_OPERAND (index, 0);
rtx index_r, pos_rtx;
HOST_WIDE_INT lo, hi, count;
tree position;
-
+
/* If the range is constant and "small", unroll the loop. */
if (const_bounds_p
&& host_integerp (lo_index, 0)
for (; lo <= hi; lo++)
{
bitpos = lo * tree_low_cst (TYPE_SIZE (elttype), 0);
-
+
if (MEM_P (target)
&& !MEM_KEEP_ALIAS_SET_P (target)
&& TREE_CODE (type) == ARRAY_TYPE
target = copy_rtx (target);
MEM_KEEP_ALIAS_SET_P (target) = 1;
}
-
+
store_constructor_field
(target, bitsize, bitpos, mode, value, type, cleared,
get_alias_set (elttype));
rtx loop_start = gen_label_rtx ();
rtx loop_end = gen_label_rtx ();
tree exit_cond;
-
+
expand_normal (hi_index);
unsignedp = TYPE_UNSIGNED (domain);
-
+
index = build_decl (VAR_DECL, NULL_TREE, domain);
-
+
index_r
= gen_reg_rtx (promote_mode (domain, DECL_MODE (index),
&unsignedp, 0));
SET_DECL_RTL (index, index_r);
- store_expr (lo_index, index_r, 0);
-
+ store_expr (lo_index, index_r, 0, false);
+
/* Build the head of the loop. */
do_pending_stack_adjust ();
emit_label (loop_start);
size_binop (MULT_EXPR, position,
fold_convert (ssizetype,
TYPE_SIZE_UNIT (elttype)));
-
+
pos_rtx = expand_normal (position);
xtarget = offset_address (target, pos_rtx,
highest_pow2_factor (position));
store_constructor (value, xtarget, cleared,
bitsize / BITS_PER_UNIT);
else
- store_expr (value, xtarget, 0);
+ store_expr (value, xtarget, 0, false);
/* Generate a conditional jump to exit the loop. */
exit_cond = build2 (LT_EXPR, integer_type_node,
index, hi_index);
jumpif (exit_cond, loop_end);
-
+
/* Update the loop counter, and jump to the head of
the loop. */
expand_assignment (index,
build2 (PLUS_EXPR, TREE_TYPE (index),
- index, integer_one_node));
-
+ index, integer_one_node),
+ false);
+
emit_jump (loop_start);
-
+
/* Build the end of the loop. */
emit_label (loop_end);
}
|| ! host_integerp (TYPE_SIZE (elttype), 1))
{
tree position;
-
+
if (index == 0)
index = ssize_int (1);
-
+
if (minelt)
index = fold_convert (ssizetype,
fold_build2 (MINUS_EXPR,
TREE_TYPE (index),
index,
TYPE_MIN_VALUE (domain)));
-
+
position =
size_binop (MULT_EXPR, index,
fold_convert (ssizetype,
expand_normal (position),
highest_pow2_factor (position));
xtarget = adjust_address (xtarget, mode, 0);
- store_expr (value, xtarget, 0);
+ store_expr (value, xtarget, 0, false);
}
else
{
* tree_low_cst (TYPE_SIZE (elttype), 1));
else
bitpos = (i * tree_low_cst (TYPE_SIZE (elttype), 1));
-
+
if (MEM_P (target) && !MEM_KEEP_ALIAS_SET_P (target)
&& TREE_CODE (type) == ARRAY_TYPE
&& TYPE_NONALIASED_COMPONENT (type))
HOST_WIDE_INT bitpos;
rtvec vector = NULL;
unsigned n_elts;
-
+
gcc_assert (eltmode != BLKmode);
-
+
n_elts = TYPE_VECTOR_SUBPARTS (type);
if (REG_P (target) && VECTOR_MODE_P (GET_MODE (target)))
{
enum machine_mode mode = GET_MODE (target);
-
+
icode = (int) vec_init_optab->handlers[mode].insn_code;
if (icode != CODE_FOR_nothing)
{
unsigned int i;
-
+
vector = rtvec_alloc (n_elts);
for (i = 0; i < n_elts; i++)
RTVEC_ELT (vector, i) = CONST0_RTX (GET_MODE_INNER (mode));
}
}
-
+
/* If the constructor has fewer elements than the vector,
clear the whole array first. Similarly if this is static
constructor of a non-BLKmode object. */
{
unsigned HOST_WIDE_INT count = 0, zero_count = 0;
tree value;
-
+
FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
{
int n_elts_here = tree_low_cst
(int_const_binop (TRUNC_DIV_EXPR,
TYPE_SIZE (TREE_TYPE (value)),
TYPE_SIZE (elttype), 0), 1);
-
+
count += n_elts_here;
if (mostly_zeros_p (value))
zero_count += n_elts_here;
or if the incidence of zero elements is >= 75%. */
need_to_clear = (count < n_elts || 4 * zero_count >= 3 * count);
}
-
+
if (need_to_clear && size > 0 && !vector)
{
if (REG_P (target))
clear_storage (target, GEN_INT (size), BLOCK_OP_NORMAL);
cleared = 1;
}
-
+
/* Inform later passes that the old value is dead. */
if (!cleared && !vector && REG_P (target))
emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
{
HOST_WIDE_INT eltpos;
tree value = ce->value;
-
+
bitsize = tree_low_cst (TYPE_SIZE (TREE_TYPE (value)), 1);
if (cleared && initializer_zerop (value))
continue;
-
+
if (ce->index)
eltpos = tree_low_cst (ce->index, 1);
else
eltpos = i;
-
+
if (vector)
{
/* Vector CONSTRUCTORs should only be built from smaller
cleared, get_alias_set (elttype));
}
}
-
+
if (vector)
emit_insn (GEN_FCN (icode)
(target,
gen_rtx_PARALLEL (GET_MODE (target), vector)));
break;
}
-
+
default:
gcc_unreachable ();
}
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. */
+ reference to the containing structure.
+
+ If NONTEMPORAL is true, try generating a nontemporal store. */
static rtx
store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
- enum machine_mode mode, tree exp, tree type, int alias_set)
+ enum machine_mode mode, tree exp, tree type, int alias_set,
+ bool nontemporal)
{
HOST_WIDE_INT width_mask = 0;
/* If we have nothing to store, do nothing unless the expression has
side-effects. */
if (bitsize == 0)
- return expand_expr (exp, const0_rtx, VOIDmode, 0);
+ return expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
else if (bitsize >= 0 && bitsize < HOST_BITS_PER_WIDE_INT)
width_mask = ((HOST_WIDE_INT) 1 << bitsize) - 1;
if (bitsize != (HOST_WIDE_INT) GET_MODE_BITSIZE (GET_MODE (target)))
emit_move_insn (object, target);
- store_field (blk_object, bitsize, bitpos, mode, exp, type, alias_set);
+ store_field (blk_object, bitsize, bitpos, mode, exp, type, alias_set,
+ nontemporal);
emit_move_insn (target, object);
/* We're storing into a struct containing a single __complex. */
gcc_assert (!bitpos);
- return store_expr (exp, target, 0);
+ return store_expr (exp, target, 0, nontemporal);
}
/* If the structure is in a register or if the component
if (!MEM_KEEP_ALIAS_SET_P (to_rtx) && MEM_ALIAS_SET (to_rtx) != 0)
set_mem_alias_set (to_rtx, alias_set);
- return store_expr (exp, to_rtx, 0);
+ return store_expr (exp, to_rtx, 0, nontemporal);
}
}
\f
{
size_tree = TREE_OPERAND (exp, 1);
*punsignedp = BIT_FIELD_REF_UNSIGNED (exp);
-
+
/* For vector types, with the correct size of access, use the mode of
inner type. */
if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == VECTOR_TYPE
return exp;
}
+/* Given an expression EXP that may be a COMPONENT_REF or an ARRAY_REF,
+ look for whether EXP or any nested component-refs within EXP is marked
+ as PACKED. */
+
+bool
+contains_packed_reference (tree exp)
+{
+ bool packed_p = false;
+
+ while (1)
+ {
+ switch (TREE_CODE (exp))
+ {
+ case COMPONENT_REF:
+ {
+ tree field = TREE_OPERAND (exp, 1);
+ packed_p = DECL_PACKED (field)
+ || TYPE_PACKED (TREE_TYPE (field))
+ || TYPE_PACKED (TREE_TYPE (exp));
+ if (packed_p)
+ goto done;
+ }
+ break;
+
+ case BIT_FIELD_REF:
+ case ARRAY_REF:
+ case ARRAY_RANGE_REF:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ case VIEW_CONVERT_EXPR:
+ break;
+
+ default:
+ goto done;
+ }
+ exp = TREE_OPERAND (exp, 0);
+ }
+ done:
+ return packed_p;
+}
+
/* Return a tree of sizetype representing the size, in bytes, of the element
of EXP, an ARRAY_REF. */
&& !REG_P (SUBREG_REG (value))
&& !MEM_P (SUBREG_REG (value)))
{
- value = simplify_gen_subreg (GET_MODE (value),
- force_reg (GET_MODE (SUBREG_REG (value)),
- force_operand (SUBREG_REG (value),
- NULL_RTX)),
- GET_MODE (SUBREG_REG (value)),
- SUBREG_BYTE (value));
+ value
+ = simplify_gen_subreg (GET_MODE (value),
+ force_reg (GET_MODE (SUBREG_REG (value)),
+ force_operand (SUBREG_REG (value),
+ NULL_RTX)),
+ GET_MODE (SUBREG_REG (value)),
+ SUBREG_BYTE (value));
code = GET_CODE (value);
}
FLOAT_MODE_P (GET_MODE (value))
? RDIV_EXPR : TRUNC_DIV_EXPR,
GET_MODE (value), op1, op2, target, 0);
- break;
case MOD:
return expand_divmod (1, TRUNC_MOD_EXPR, GET_MODE (value), op1, op2,
target, 0);
- break;
case UDIV:
return expand_divmod (0, TRUNC_DIV_EXPR, GET_MODE (value), op1, op2,
target, 1);
- break;
case UMOD:
return expand_divmod (1, TRUNC_MOD_EXPR, GET_MODE (value), op1, op2,
target, 1);
- break;
case ASHIFTRT:
return expand_simple_binop (GET_MODE (value), code, op1, op2,
target, 0, OPTAB_LIB_WIDEN);
- break;
default:
return expand_simple_binop (GET_MODE (value), code, op1, op2,
target, 1, OPTAB_LIB_WIDEN);
if (modifier != EXPAND_NORMAL)
result = force_operand (result, NULL);
- tmp = expand_expr (offset, NULL, tmode, EXPAND_NORMAL);
+ tmp = expand_expr (offset, NULL_RTX, tmode,
+ modifier == EXPAND_INITIALIZER
+ ? EXPAND_INITIALIZER : EXPAND_NORMAL);
result = convert_memory_address (tmode, result);
tmp = convert_memory_address (tmode, tmp);
case RESULT_DECL:
decl_rtl = DECL_RTL (exp);
gcc_assert (decl_rtl);
+ decl_rtl = copy_rtx (decl_rtl);
/* 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
&& 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_mode (type, DECL_MODE (exp), &unsignedp,
temp = immed_double_const (TREE_INT_CST_LOW (exp),
TREE_INT_CST_HIGH (exp), mode);
- /* ??? If overflow is set, fold will have done an incomplete job,
- which can result in (plus xx (const_int 0)), which can get
- simplified by validate_replace_rtx during virtual register
- instantiation, which can result in unrecognizable insns.
- Avoid this by forcing all overflows into registers. */
- if (TREE_OVERFLOW (exp)
- && modifier != EXPAND_INITIALIZER)
- temp = force_reg (mode, temp);
-
return temp;
case VECTOR_CST:
itarg = XEXP (original_target, 1);
/* Move the real and imaginary parts separately. */
- op0 = expand_expr (TREE_REALPART (exp), rtarg, mode, 0);
- op1 = expand_expr (TREE_IMAGPART (exp), itarg, mode, 0);
+ op0 = expand_expr (TREE_REALPART (exp), rtarg, mode, EXPAND_NORMAL);
+ op1 = expand_expr (TREE_IMAGPART (exp), itarg, mode, EXPAND_NORMAL);
if (op0 != rtarg)
emit_move_insn (rtarg, op0);
tree value;
FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
- expand_expr (value, const0_rtx, VOIDmode, 0);
+ expand_expr (value, const0_rtx, VOIDmode, EXPAND_NORMAL);
return const0_rtx;
}
tree index1 = index;
tree low_bound = array_ref_low_bound (exp);
index1 = fold_convert (sizetype, TREE_OPERAND (exp, 1));
-
+
/* 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 (index1, fold_convert (sizetype,
low_bound));
-
+
if (0 > compare_tree_int (index1,
TREE_STRING_LENGTH (init)))
{
/* Store data into beginning of memory target. */
store_expr (TREE_OPERAND (exp, 0),
adjust_address (target, TYPE_MODE (valtype), 0),
- modifier == EXPAND_STACK_PARM);
+ modifier == EXPAND_STACK_PARM,
+ false);
else
{
gcc_assert (REG_P (target));
-
+
/* Store this field into a union of the proper type. */
store_field (target,
MIN ((int_size_in_bytes (TREE_TYPE
* BITS_PER_UNIT),
(HOST_WIDE_INT) GET_MODE_BITSIZE (mode)),
0, TYPE_MODE (valtype), TREE_OPERAND (exp, 0),
- type, 0);
+ type, 0, false);
}
/* Return the entire union. */
other. */
else if (SCALAR_INT_MODE_P (GET_MODE (op0))
&& SCALAR_INT_MODE_P (TYPE_MODE (type)))
- op0 = convert_modes (TYPE_MODE (type), GET_MODE (op0), op0,
+ op0 = convert_modes (TYPE_MODE (type), GET_MODE (op0), op0,
TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
- /* As a last resort, spill op0 to memory, and reload it in a
+ /* As a last resort, spill op0 to memory, and reload it in a
different mode. */
else if (!MEM_P (op0))
{
return op0;
+ 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
+ of the PLUS_EXPR code. */
case PLUS_EXPR:
+
/* Check if this is a case for multiplication and addition. */
if (TREE_CODE (type) == INTEGER_TYPE
&& TREE_CODE (TREE_OPERAND (exp, 0)) == MULT_EXPR)
TREE_OPERAND (subsubexp1, 0),
NULL_RTX, &op0, &op1, EXPAND_NORMAL);
op2 = expand_expr (TREE_OPERAND (exp, 1), subtarget,
- VOIDmode, 0);
+ VOIDmode, EXPAND_NORMAL);
temp = expand_ternary_op (mode, this_optab, op0, op1, op2,
target, unsignedp);
gcc_assert (temp);
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 (TREE_OPERAND (exp, 1)) == MULT_EXPR)
+ {
+ tree subsubexp0, subsubexp1;
+ enum tree_code code0, code1;
+
+ subexp1 = TREE_OPERAND (exp, 1);
+ subsubexp0 = TREE_OPERAND (subexp1, 0);
+ subsubexp1 = TREE_OPERAND (subexp1, 1);
+ code0 = TREE_CODE (subsubexp0);
+ code1 = TREE_CODE (subsubexp1);
+ if (code0 == NOP_EXPR && code1 == NOP_EXPR
+ && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
+ < TYPE_PRECISION (TREE_TYPE (subsubexp0)))
+ && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
+ == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp1, 0))))
+ && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
+ == TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp1, 0)))))
+ {
+ tree op0type = TREE_TYPE (TREE_OPERAND (subsubexp0, 0));
+ enum machine_mode innermode = TYPE_MODE (op0type);
+ bool zextend_p = TYPE_UNSIGNED (op0type);
+ this_optab = zextend_p ? umsub_widen_optab : smsub_widen_optab;
+ if (mode == GET_MODE_2XWIDER_MODE (innermode)
+ && (this_optab->handlers[(int) mode].insn_code
+ != CODE_FOR_nothing))
+ {
+ expand_operands (TREE_OPERAND (subsubexp0, 0),
+ TREE_OPERAND (subsubexp1, 0),
+ NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+ op2 = expand_expr (TREE_OPERAND (exp, 0), 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. */
return target;
case NEGATE_EXPR:
- op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+ op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget,
+ VOIDmode, EXPAND_NORMAL);
if (modifier == EXPAND_STACK_PARM)
target = 0;
temp = expand_unop (mode,
return REDUCE_BIT_FIELD (temp);
case ABS_EXPR:
- op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+ op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget,
+ VOIDmode, EXPAND_NORMAL);
if (modifier == EXPAND_STACK_PARM)
target = 0;
return target;
case BIT_NOT_EXPR:
- op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+ op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget,
+ VOIDmode, EXPAND_NORMAL);
if (modifier == EXPAND_STACK_PARM)
target = 0;
temp = expand_unop (mode, one_cmpl_optab, op0, target, 1);
subtarget = 0;
if (modifier == EXPAND_STACK_PARM)
target = 0;
- op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+ op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget,
+ VOIDmode, EXPAND_NORMAL);
return expand_shift (code, mode, op0, TREE_OPERAND (exp, 1), target,
unsignedp);
== TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
{
temp = expand_expr (TREE_OPERAND (exp, 0), original_target,
- VOIDmode, 0);
+ VOIDmode, EXPAND_NORMAL);
/* If temp is constant, we can just compute the result. */
if (GET_CODE (temp) == CONST_INT)
case TRUTH_NOT_EXPR:
if (modifier == EXPAND_STACK_PARM)
target = 0;
- op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
+ op0 = expand_expr (TREE_OPERAND (exp, 0), target,
+ VOIDmode, EXPAND_NORMAL);
/* The parser is careful to generate TRUTH_NOT_EXPR
only with operands that are always zero or one. */
temp = expand_binop (mode, xor_optab, op0, const1_rtx,
op1 = gen_label_rtx ();
jumpifnot (TREE_OPERAND (exp, 0), op0);
store_expr (TREE_OPERAND (exp, 1), temp,
- modifier == EXPAND_STACK_PARM);
+ modifier == EXPAND_STACK_PARM,
+ false);
emit_jump_insn (gen_jump (op1));
emit_barrier ();
emit_label (op0);
store_expr (TREE_OPERAND (exp, 2), temp,
- modifier == EXPAND_STACK_PARM);
+ modifier == EXPAND_STACK_PARM,
+ false);
emit_label (op1);
OK_DEFER_POP;
tree lhs = TREE_OPERAND (exp, 0);
tree rhs = TREE_OPERAND (exp, 1);
gcc_assert (ignore);
- expand_assignment (lhs, rhs);
+ expand_assignment (lhs, rhs, false);
return const0_rtx;
}
do_jump (TREE_OPERAND (rhs, 1),
value ? label : 0,
value ? 0 : label);
- expand_assignment (lhs, build_int_cst (TREE_TYPE (rhs), value));
+ expand_assignment (lhs, build_int_cst (TREE_TYPE (rhs), value),
+ MOVE_NONTEMPORAL (exp));
do_pending_stack_adjust ();
emit_label (label);
return const0_rtx;
}
- expand_assignment (lhs, rhs);
+ expand_assignment (lhs, rhs, MOVE_NONTEMPORAL (exp));
return const0_rtx;
}
/* Lowered by gimplify.c. */
gcc_unreachable ();
+ case CHANGE_DYNAMIC_TYPE_EXPR:
+ /* This is ignored at the RTL level. The tree level set
+ DECL_POINTER_ALIAS_SET of any variable to be 0, which is
+ overkill for the RTL layer but is all that we can
+ represent. */
+ return const0_rtx;
+
case EXC_PTR_EXPR:
return get_exception_pointer (cfun);
case REALIGN_LOAD_EXPR:
{
- tree oprnd0 = TREE_OPERAND (exp, 0);
+ tree oprnd0 = TREE_OPERAND (exp, 0);
tree oprnd1 = TREE_OPERAND (exp, 1);
tree oprnd2 = TREE_OPERAND (exp, 2);
rtx op2;
this_optab = optab_for_tree_code (code, type);
expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
op2 = expand_normal (oprnd2);
- temp = expand_ternary_op (mode, this_optab, op0, op1, op2,
+ temp = expand_ternary_op (mode, this_optab, op0, op1, op2,
target, unsignedp);
gcc_assert (temp);
return temp;
expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
op2 = expand_normal (oprnd2);
- target = expand_widen_pattern_expr (exp, op0, op1, op2,
+ target = expand_widen_pattern_expr (exp, op0, op1, op2,
target, unsignedp);
return target;
}
{
tree oprnd0 = TREE_OPERAND (exp, 0);
tree oprnd1 = TREE_OPERAND (exp, 1);
-
+
expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, 0);
target = expand_widen_pattern_expr (exp, op0, NULL_RTX, op1,
target, unsignedp);
case VEC_UNPACK_HI_EXPR:
case VEC_UNPACK_LO_EXPR:
{
- op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
+ op0 = expand_normal (TREE_OPERAND (exp, 0));
this_optab = optab_for_tree_code (code, type);
temp = expand_widen_pattern_expr (exp, op0, NULL_RTX, NULL_RTX,
target, unsignedp);
return temp;
}
+ case VEC_UNPACK_FLOAT_HI_EXPR:
+ case VEC_UNPACK_FLOAT_LO_EXPR:
+ {
+ op0 = expand_normal (TREE_OPERAND (exp, 0));
+ /* The signedness is determined from input operand. */
+ this_optab = optab_for_tree_code (code,
+ TREE_TYPE (TREE_OPERAND (exp, 0)));
+ temp = expand_widen_pattern_expr
+ (exp, op0, NULL_RTX, NULL_RTX,
+ target, TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
+
+ gcc_assert (temp);
+ return temp;
+ }
+
case VEC_WIDEN_MULT_HI_EXPR:
case VEC_WIDEN_MULT_LO_EXPR:
{
case VEC_PACK_TRUNC_EXPR:
case VEC_PACK_SAT_EXPR:
+ case VEC_PACK_FIX_TRUNC_EXPR:
{
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
goto binop;
if (TREE_CODE (offset) != INTEGER_CST)
return 0;
/* Adjust offset by the lower bound. */
- offset = size_diffop (fold_convert (sizetype, offset),
+ offset = size_diffop (fold_convert (sizetype, offset),
fold_convert (sizetype, lower_bound));
}
}
else
return 0;
}
- else if (TREE_CODE (arg) == PLUS_EXPR)
+ else if (TREE_CODE (arg) == PLUS_EXPR || TREE_CODE (arg) == POINTER_PLUS_EXPR)
{
tree arg0 = TREE_OPERAND (arg, 0);
tree arg1 = TREE_OPERAND (arg, 1);
if (icode == CODE_FOR_nothing)
{
enum machine_mode wmode;
-
+
for (wmode = operand_mode;
icode == CODE_FOR_nothing && wmode != VOIDmode;
wmode = GET_MODE_WIDER_MODE (wmode))
label = gen_label_rtx ();
do_compare_rtx_and_jump (op0, op1, code, unsignedp, operand_mode, NULL_RTX,
NULL_RTX, label);
-
+
emit_move_insn (target, invert ? const1_rtx : const0_rtx);
emit_label (label);