aboutsummaryrefslogtreecommitdiff
path: root/gcc/expr.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/expr.c')
-rw-r--r--gcc/expr.c328
1 files changed, 211 insertions, 117 deletions
diff --git a/gcc/expr.c b/gcc/expr.c
index 11c25315238..050642daa4f 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -121,11 +121,11 @@ static rtx_insn *compress_float_constant (rtx, rtx);
static rtx get_subtarget (rtx);
static void store_constructor_field (rtx, unsigned HOST_WIDE_INT,
HOST_WIDE_INT, machine_mode,
- tree, int, alias_set_type);
-static void store_constructor (tree, rtx, int, HOST_WIDE_INT);
+ tree, int, alias_set_type, bool);
+static void store_constructor (tree, rtx, int, HOST_WIDE_INT, bool);
static rtx store_field (rtx, HOST_WIDE_INT, HOST_WIDE_INT,
unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
- machine_mode, tree, alias_set_type, bool);
+ machine_mode, tree, alias_set_type, bool, bool);
static unsigned HOST_WIDE_INT highest_pow2_factor_for_target (const_tree, const_tree);
@@ -1678,7 +1678,7 @@ emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type, int ssize)
&& (!REG_P (tmps[i]) || GET_MODE (tmps[i]) != mode))
tmps[i] = extract_bit_field (tmps[i], bytelen * BITS_PER_UNIT,
(bytepos % slen0) * BITS_PER_UNIT,
- 1, NULL_RTX, mode, mode);
+ 1, NULL_RTX, mode, mode, false);
}
else
{
@@ -1688,7 +1688,7 @@ emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type, int ssize)
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, NULL_RTX, mode, mode);
+ 0, 1, NULL_RTX, mode, mode, false);
}
}
/* FIXME: A SIMD parallel will eventually lead to a subreg of a
@@ -1731,7 +1731,7 @@ emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type, int ssize)
else
tmps[i] = extract_bit_field (src, bytelen * BITS_PER_UNIT,
bytepos * BITS_PER_UNIT, 1, NULL_RTX,
- mode, mode);
+ mode, mode, false);
if (shift)
tmps[i] = expand_shift (LSHIFT_EXPR, mode, tmps[i],
@@ -2039,7 +2039,7 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
store_bit_field (dest,
adj_bytelen * BITS_PER_UNIT, bytepos * BITS_PER_UNIT,
bytepos * BITS_PER_UNIT, ssize * BITS_PER_UNIT - 1,
- VOIDmode, tmps[i]);
+ VOIDmode, tmps[i], false);
}
/* Optimize the access just a bit. */
@@ -2052,7 +2052,7 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
else
store_bit_field (dest, bytelen * BITS_PER_UNIT, bytepos * BITS_PER_UNIT,
- 0, 0, mode, tmps[i]);
+ 0, 0, mode, tmps[i], false);
}
/* Copy from the pseudo into the (probable) hard reg. */
@@ -2182,7 +2182,9 @@ copy_blkmode_from_reg (rtx target, rtx srcreg, tree type)
store_bit_field (dst, bitsize, bitpos % BITS_PER_WORD, 0, 0, copy_mode,
extract_bit_field (src, bitsize,
xbitpos % BITS_PER_WORD, 1,
- NULL_RTX, copy_mode, copy_mode));
+ NULL_RTX, copy_mode, copy_mode,
+ false),
+ false);
}
}
@@ -2259,7 +2261,9 @@ copy_blkmode_to_reg (machine_mode mode, tree src)
0, 0, word_mode,
extract_bit_field (src_word, bitsize,
bitpos % BITS_PER_WORD, 1,
- NULL_RTX, word_mode, word_mode));
+ NULL_RTX, word_mode, word_mode,
+ false),
+ false);
}
if (mode == BLKmode)
@@ -3004,7 +3008,8 @@ write_complex_part (rtx cplx, rtx val, bool imag_p)
gcc_assert (MEM_P (cplx) && ibitsize < BITS_PER_WORD);
}
- store_bit_field (cplx, ibitsize, imag_p ? ibitsize : 0, 0, 0, imode, val);
+ store_bit_field (cplx, ibitsize, imag_p ? ibitsize : 0, 0, 0, imode, val,
+ false);
}
/* Extract one of the components of the complex value CPLX. Extract the
@@ -3067,7 +3072,7 @@ read_complex_part (rtx cplx, bool imag_p)
}
return extract_bit_field (cplx, ibitsize, imag_p ? ibitsize : 0,
- true, NULL_RTX, imode, imode);
+ true, NULL_RTX, imode, imode, false);
}
/* A subroutine of emit_move_insn_1. Yet another lowpart generator.
@@ -4457,7 +4462,7 @@ optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize,
unsigned HOST_WIDE_INT bitregion_start,
unsigned HOST_WIDE_INT bitregion_end,
machine_mode mode1, rtx str_rtx,
- tree to, tree src)
+ tree to, tree src, bool reverse)
{
machine_mode str_mode = GET_MODE (str_rtx);
unsigned int str_bitsize = GET_MODE_BITSIZE (str_mode);
@@ -4530,6 +4535,8 @@ optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize,
}
else if (!REG_P (str_rtx) && GET_CODE (str_rtx) != SUBREG)
return false;
+ else
+ gcc_assert (!reverse);
/* If the bit field covers the whole REG/MEM, store_field
will likely generate better code. */
@@ -4540,7 +4547,7 @@ optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize,
if (bitpos + bitsize > str_bitsize)
return false;
- if (BYTES_BIG_ENDIAN)
+ if (reverse ? !BYTES_BIG_ENDIAN : BYTES_BIG_ENDIAN)
bitpos = str_bitsize - bitpos - bitsize;
switch (code)
@@ -4553,7 +4560,7 @@ optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize,
We might win by one instruction for the other bitfields
too if insv/extv instructions aren't used, so that
can be added later. */
- if (bitpos + bitsize != str_bitsize
+ if ((reverse || bitpos + bitsize != str_bitsize)
&& (bitsize != 1 || TREE_CODE (op1) != INTEGER_CST))
break;
@@ -4571,13 +4578,17 @@ optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize,
set_mem_expr (str_rtx, 0);
}
- binop = code == PLUS_EXPR ? add_optab : sub_optab;
- if (bitsize == 1 && bitpos + bitsize != str_bitsize)
+ if (bitsize == 1 && (reverse || bitpos + bitsize != str_bitsize))
{
value = expand_and (str_mode, value, const1_rtx, NULL);
binop = xor_optab;
}
+ else
+ binop = code == PLUS_EXPR ? add_optab : sub_optab;
+
value = expand_shift (LSHIFT_EXPR, str_mode, value, bitpos, NULL_RTX, 1);
+ if (reverse)
+ value = flip_storage_order (str_mode, value);
result = expand_binop (str_mode, binop, str_rtx,
value, str_rtx, 1, OPTAB_WIDEN);
if (result != str_rtx)
@@ -4610,6 +4621,8 @@ optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize,
value = expand_and (str_mode, value, mask, NULL_RTX);
}
value = expand_shift (LSHIFT_EXPR, str_mode, value, bitpos, NULL_RTX, 1);
+ if (reverse)
+ value = flip_storage_order (str_mode, value);
result = expand_binop (str_mode, binop, str_rtx,
value, str_rtx, 1, OPTAB_WIDEN);
if (result != str_rtx)
@@ -4664,10 +4677,10 @@ get_bit_range (unsigned HOST_WIDE_INT *bitstart,
machine_mode rmode;
HOST_WIDE_INT rbitsize, rbitpos;
tree roffset;
- int unsignedp;
- int volatilep = 0;
+ int unsignedp, reversep, volatilep = 0;
get_inner_reference (TREE_OPERAND (exp, 0), &rbitsize, &rbitpos,
- &roffset, &rmode, &unsignedp, &volatilep, false);
+ &roffset, &rmode, &unsignedp, &reversep,
+ &volatilep, false);
if ((rbitpos % BITS_PER_UNIT) != 0)
{
*bitstart = *bitend = 0;
@@ -4783,6 +4796,8 @@ expand_assignment (tree to, tree from, bool nontemporal)
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 && REF_REVERSE_STORAGE_ORDER (to))
+ reg = flip_storage_order (mode, reg);
if (icode != CODE_FOR_nothing)
{
@@ -4795,7 +4810,8 @@ expand_assignment (tree to, tree from, bool nontemporal)
expand_insn (icode, 2, ops);
}
else
- store_bit_field (mem, GET_MODE_BITSIZE (mode), 0, 0, 0, mode, reg);
+ store_bit_field (mem, GET_MODE_BITSIZE (mode), 0, 0, 0, mode, reg,
+ false);
return;
}
@@ -4806,7 +4822,8 @@ expand_assignment (tree to, tree from, bool nontemporal)
problem. Same for (partially) storing into a non-memory object. */
if (handled_component_p (to)
|| (TREE_CODE (to) == MEM_REF
- && mem_ref_refers_to_non_mem_p (to))
+ && (REF_REVERSE_STORAGE_ORDER (to)
+ || mem_ref_refers_to_non_mem_p (to)))
|| TREE_CODE (TREE_TYPE (to)) == ARRAY_TYPE)
{
machine_mode mode1;
@@ -4814,13 +4831,12 @@ expand_assignment (tree to, tree from, bool nontemporal)
unsigned HOST_WIDE_INT bitregion_start = 0;
unsigned HOST_WIDE_INT bitregion_end = 0;
tree offset;
- int unsignedp;
- int volatilep = 0;
+ int unsignedp, reversep, volatilep = 0;
tree tem;
push_temp_slots ();
tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1,
- &unsignedp, &volatilep, true);
+ &unsignedp, &reversep, &volatilep, true);
/* Make sure bitpos is not negative, it can wreak havoc later. */
if (bitpos < 0)
@@ -4939,22 +4955,22 @@ expand_assignment (tree to, tree from, bool nontemporal)
if (COMPLEX_MODE_P (TYPE_MODE (TREE_TYPE (from)))
&& bitpos == 0
&& bitsize == mode_bitsize)
- result = store_expr (from, to_rtx, false, nontemporal);
+ result = store_expr (from, to_rtx, false, nontemporal, reversep);
else if (bitsize == mode_bitsize / 2
&& (bitpos == 0 || bitpos == mode_bitsize / 2))
result = store_expr (from, XEXP (to_rtx, bitpos != 0), false,
- nontemporal);
+ nontemporal, reversep);
else if (bitpos + bitsize <= mode_bitsize / 2)
result = store_field (XEXP (to_rtx, 0), bitsize, bitpos,
bitregion_start, bitregion_end,
- mode1, from,
- get_alias_set (to), nontemporal);
+ mode1, from, get_alias_set (to),
+ nontemporal, reversep);
else if (bitpos >= mode_bitsize / 2)
result = store_field (XEXP (to_rtx, 1), bitsize,
bitpos - mode_bitsize / 2,
bitregion_start, bitregion_end,
- mode1, from,
- get_alias_set (to), nontemporal);
+ mode1, from, get_alias_set (to),
+ nontemporal, reversep);
else if (bitpos == 0 && bitsize == mode_bitsize)
{
rtx from_rtx;
@@ -4974,8 +4990,8 @@ expand_assignment (tree to, tree from, bool nontemporal)
write_complex_part (temp, XEXP (to_rtx, 1), true);
result = store_field (temp, bitsize, bitpos,
bitregion_start, bitregion_end,
- mode1, from,
- get_alias_set (to), nontemporal);
+ mode1, from, get_alias_set (to),
+ nontemporal, reversep);
emit_move_insn (XEXP (to_rtx, 0), read_complex_part (temp, false));
emit_move_insn (XEXP (to_rtx, 1), read_complex_part (temp, true));
}
@@ -4994,14 +5010,14 @@ expand_assignment (tree to, tree from, bool nontemporal)
if (optimize_bitfield_assignment_op (bitsize, bitpos,
bitregion_start, bitregion_end,
- mode1,
- to_rtx, to, from))
+ mode1, to_rtx, to, from,
+ reversep))
result = NULL;
else
result = store_field (to_rtx, bitsize, bitpos,
bitregion_start, bitregion_end,
- mode1, from,
- get_alias_set (to), nontemporal);
+ mode1, from, get_alias_set (to),
+ nontemporal, reversep);
}
if (result)
@@ -5155,7 +5171,7 @@ expand_assignment (tree to, tree from, bool nontemporal)
/* Compute FROM and store the value in the rtx we got. */
push_temp_slots ();
- result = store_expr_with_bounds (from, to_rtx, 0, nontemporal, to);
+ result = store_expr_with_bounds (from, to_rtx, 0, nontemporal, false, to);
preserve_temp_slots (result);
pop_temp_slots ();
return;
@@ -5194,12 +5210,14 @@ emit_storent_insn (rtx to, rtx from)
If NONTEMPORAL is true, try using a nontemporal store instruction.
+ If REVERSE is true, the store is to be done in reverse order.
+
If BTARGET is not NULL then computed bounds of EXP are
associated with BTARGET. */
rtx
store_expr_with_bounds (tree exp, rtx target, int call_param_p,
- bool nontemporal, tree btarget)
+ bool nontemporal, bool reverse, tree btarget)
{
rtx temp;
rtx alt_rtl = NULL_RTX;
@@ -5221,7 +5239,8 @@ store_expr_with_bounds (tree exp, rtx target, int call_param_p,
expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
call_param_p ? EXPAND_STACK_PARM : EXPAND_NORMAL);
return store_expr_with_bounds (TREE_OPERAND (exp, 1), target,
- call_param_p, nontemporal, btarget);
+ call_param_p, nontemporal, reverse,
+ btarget);
}
else if (TREE_CODE (exp) == COND_EXPR && GET_MODE (target) == BLKmode)
{
@@ -5236,12 +5255,12 @@ store_expr_with_bounds (tree exp, rtx target, int call_param_p,
NO_DEFER_POP;
jumpifnot (TREE_OPERAND (exp, 0), lab1, -1);
store_expr_with_bounds (TREE_OPERAND (exp, 1), target, call_param_p,
- nontemporal, btarget);
+ nontemporal, reverse, btarget);
emit_jump_insn (targetm.gen_jump (lab2));
emit_barrier ();
emit_label (lab1);
store_expr_with_bounds (TREE_OPERAND (exp, 2), target, call_param_p,
- nontemporal, btarget);
+ nontemporal, reverse, btarget);
emit_label (lab2);
OK_DEFER_POP;
@@ -5380,9 +5399,9 @@ store_expr_with_bounds (tree exp, rtx target, int call_param_p,
rtx tmp_target;
normal_expr:
- /* If we want to use a nontemporal store, force the value to
- register first. */
- tmp_target = nontemporal ? NULL_RTX : target;
+ /* If we want to use a nontemporal or a reverse order store, force the
+ value into a register first. */
+ tmp_target = nontemporal || reverse ? NULL_RTX : target;
temp = expand_expr_real (exp, tmp_target, GET_MODE (target),
(call_param_p
? EXPAND_STACK_PARM : EXPAND_NORMAL),
@@ -5457,7 +5476,7 @@ store_expr_with_bounds (tree exp, rtx target, int call_param_p,
else
store_bit_field (target,
INTVAL (expr_size (exp)) * BITS_PER_UNIT,
- 0, 0, 0, GET_MODE (temp), temp);
+ 0, 0, 0, GET_MODE (temp), temp, reverse);
}
else
convert_move (target, temp, TYPE_UNSIGNED (TREE_TYPE (exp)));
@@ -5556,6 +5575,8 @@ store_expr_with_bounds (tree exp, rtx target, int call_param_p,
;
else
{
+ if (reverse)
+ temp = flip_storage_order (GET_MODE (target), temp);
temp = force_operand (temp, target);
if (temp != target)
emit_move_insn (target, temp);
@@ -5567,9 +5588,11 @@ store_expr_with_bounds (tree exp, rtx target, int call_param_p,
/* Same as store_expr_with_bounds but ignoring bounds of EXP. */
rtx
-store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
+store_expr (tree exp, rtx target, int call_param_p, bool nontemporal,
+ bool reverse)
{
- return store_expr_with_bounds (exp, target, call_param_p, nontemporal, NULL);
+ return store_expr_with_bounds (exp, target, call_param_p, nontemporal,
+ reverse, NULL);
}
/* Return true if field F of structure TYPE is a flexible array. */
@@ -5789,8 +5812,12 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
init_elts += mult * tc;
if (const_from_elts_p && const_p)
- const_p = initializer_constant_valid_p (value, elt_type)
- != NULL_TREE;
+ const_p
+ = initializer_constant_valid_p (value,
+ elt_type,
+ TYPE_REVERSE_STORAGE_ORDER
+ (TREE_TYPE (ctor)))
+ != NULL_TREE;
}
break;
}
@@ -5895,6 +5922,7 @@ all_zeros_p (const_tree exp)
TARGET, BITSIZE, BITPOS, MODE, EXP are as for store_field.
CLEARED is as for store_constructor.
ALIAS_SET is the alias set to use for any stores.
+ If REVERSE is true, the store is to be done in reverse order.
This provides a recursive shortcut back to store_constructor when it isn't
necessary to go through store_field. This is so that we can pass through
@@ -5904,7 +5932,8 @@ all_zeros_p (const_tree exp)
static void
store_constructor_field (rtx target, unsigned HOST_WIDE_INT bitsize,
HOST_WIDE_INT bitpos, machine_mode mode,
- tree exp, int cleared, alias_set_type alias_set)
+ tree exp, int cleared,
+ alias_set_type alias_set, bool reverse)
{
if (TREE_CODE (exp) == CONSTRUCTOR
/* We can only call store_constructor recursively if the size and
@@ -5933,10 +5962,12 @@ store_constructor_field (rtx target, unsigned HOST_WIDE_INT bitsize,
set_mem_alias_set (target, alias_set);
}
- store_constructor (exp, target, cleared, bitsize / BITS_PER_UNIT);
+ store_constructor (exp, target, cleared, bitsize / BITS_PER_UNIT,
+ reverse);
}
else
- store_field (target, bitsize, bitpos, 0, 0, mode, exp, alias_set, false);
+ store_field (target, bitsize, bitpos, 0, 0, mode, exp, alias_set, false,
+ reverse);
}
@@ -5962,10 +5993,12 @@ fields_length (const_tree type)
CLEARED is true if TARGET is known to have been zero'd.
SIZE is the number of bytes of TARGET we are allowed to modify: this
may not be the same as the size of EXP if we are assigning to a field
- which has been packed to exclude padding bits. */
+ which has been packed to exclude padding bits.
+ If REVERSE is true, the store is to be done in reverse order. */
static void
-store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
+store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size,
+ bool reverse)
{
tree type = TREE_TYPE (exp);
HOST_WIDE_INT exp_size = int_size_in_bytes (type);
@@ -5979,6 +6012,9 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
unsigned HOST_WIDE_INT idx;
tree field, value;
+ /* The storage order is specified for every aggregate type. */
+ reverse = TYPE_REVERSE_STORAGE_ORDER (type);
+
/* If size is zero or the target is already cleared, do nothing. */
if (size == 0 || cleared)
cleared = 1;
@@ -6122,7 +6158,8 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
store_constructor_field (to_rtx, bitsize, bitpos, mode,
value, cleared,
- get_alias_set (TREE_TYPE (field)));
+ get_alias_set (TREE_TYPE (field)),
+ reverse);
}
break;
}
@@ -6137,6 +6174,9 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
HOST_WIDE_INT minelt = 0;
HOST_WIDE_INT maxelt = 0;
+ /* The storage order is specified for every aggregate type. */
+ reverse = TYPE_REVERSE_STORAGE_ORDER (type);
+
domain = TYPE_DOMAIN (type);
const_bounds_p = (TYPE_MIN_VALUE (domain)
&& TYPE_MAX_VALUE (domain)
@@ -6277,7 +6317,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
store_constructor_field
(target, bitsize, bitpos, mode, value, cleared,
- get_alias_set (elttype));
+ get_alias_set (elttype), reverse);
}
}
else
@@ -6292,7 +6332,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
VAR_DECL, NULL_TREE, domain);
index_r = gen_reg_rtx (promote_decl_mode (index, NULL));
SET_DECL_RTL (index, index_r);
- store_expr (lo_index, index_r, 0, false);
+ store_expr (lo_index, index_r, 0, false, reverse);
/* Build the head of the loop. */
do_pending_stack_adjust ();
@@ -6317,9 +6357,9 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
xtarget = adjust_address (xtarget, mode, 0);
if (TREE_CODE (value) == CONSTRUCTOR)
store_constructor (value, xtarget, cleared,
- bitsize / BITS_PER_UNIT);
+ bitsize / BITS_PER_UNIT, reverse);
else
- store_expr (value, xtarget, 0, false);
+ store_expr (value, xtarget, 0, false, reverse);
/* Generate a conditional jump to exit the loop. */
exit_cond = build2 (LT_EXPR, integer_type_node,
@@ -6362,7 +6402,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
expand_normal (position),
highest_pow2_factor (position));
xtarget = adjust_address (xtarget, mode, 0);
- store_expr (value, xtarget, 0, false);
+ store_expr (value, xtarget, 0, false, reverse);
}
else
{
@@ -6380,7 +6420,8 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
MEM_KEEP_ALIAS_SET_P (target) = 1;
}
store_constructor_field (target, bitsize, bitpos, mode, value,
- cleared, get_alias_set (elttype));
+ cleared, get_alias_set (elttype),
+ reverse);
}
}
break;
@@ -6513,7 +6554,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
: eltmode;
bitpos = eltpos * elt_size;
store_constructor_field (target, bitsize, bitpos, value_mode,
- value, cleared, alias);
+ value, cleared, alias, reverse);
}
}
@@ -6546,14 +6587,16 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
(in general) be different from that for TARGET, since TARGET is a
reference to the containing structure.
- If NONTEMPORAL is true, try generating a nontemporal store. */
+ If NONTEMPORAL is true, try generating a nontemporal store.
+
+ If REVERSE is true, the store is to be done in reverse order. */
static rtx
store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
unsigned HOST_WIDE_INT bitregion_start,
unsigned HOST_WIDE_INT bitregion_end,
machine_mode mode, tree exp,
- alias_set_type alias_set, bool nontemporal)
+ alias_set_type alias_set, bool nontemporal, bool reverse)
{
if (TREE_CODE (exp) == ERROR_MARK)
return const0_rtx;
@@ -6568,7 +6611,7 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
/* We're storing into a struct containing a single __complex. */
gcc_assert (!bitpos);
- return store_expr (exp, target, 0, nontemporal);
+ return store_expr (exp, target, 0, nontemporal, reverse);
}
/* If the structure is in a register or if the component
@@ -6637,16 +6680,27 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
temp = expand_normal (exp);
- /* If BITSIZE is narrower than the size of the type of EXP
- we will be narrowing TEMP. Normally, what's wanted are the
- low-order bits. However, if EXP's type is a record and this is
- big-endian machine, we want the upper BITSIZE bits. */
- if (BYTES_BIG_ENDIAN && GET_MODE_CLASS (GET_MODE (temp)) == MODE_INT
- && bitsize < (HOST_WIDE_INT) GET_MODE_BITSIZE (GET_MODE (temp))
- && TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
- temp = expand_shift (RSHIFT_EXPR, GET_MODE (temp), temp,
- GET_MODE_BITSIZE (GET_MODE (temp)) - bitsize,
- NULL_RTX, 1);
+ /* If the value has a record type and an integral mode then, if BITSIZE
+ is narrower than this mode and this is for big-endian data, we must
+ first put the value into the low-order bits. Moreover, the field may
+ be not aligned on a byte boundary; in this case, if it has reverse
+ storage order, it needs to be accessed as a scalar field with reverse
+ storage order and we must first put the value into target order. */
+ if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
+ && GET_MODE_CLASS (GET_MODE (temp)) == MODE_INT)
+ {
+ HOST_WIDE_INT size = GET_MODE_BITSIZE (GET_MODE (temp));
+
+ reverse = TYPE_REVERSE_STORAGE_ORDER (TREE_TYPE (exp));
+
+ if (reverse)
+ temp = flip_storage_order (GET_MODE (temp), temp);
+
+ if (bitsize < size
+ && reverse ? !BYTES_BIG_ENDIAN : BYTES_BIG_ENDIAN)
+ temp = expand_shift (RSHIFT_EXPR, GET_MODE (temp), temp,
+ size - bitsize, NULL_RTX, 1);
+ }
/* Unless MODE is VOIDmode or BLKmode, convert TEMP to MODE. */
if (mode != VOIDmode && mode != BLKmode
@@ -6706,7 +6760,7 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
temp_target = gen_reg_rtx (mode);
temp_target
= extract_bit_field (temp, size * BITS_PER_UNIT, 0, 1,
- temp_target, mode, mode);
+ temp_target, mode, mode, false);
temp = temp_target;
}
}
@@ -6714,7 +6768,7 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
/* Store the value in the bitfield. */
store_bit_field (target, bitsize, bitpos,
bitregion_start, bitregion_end,
- mode, temp);
+ mode, temp, reverse);
return const0_rtx;
}
@@ -6734,11 +6788,11 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
if (TREE_CODE (exp) == CONSTRUCTOR && bitsize >= 0)
{
gcc_assert (bitsize % BITS_PER_UNIT == 0);
- store_constructor (exp, to_rtx, 0, bitsize/BITS_PER_UNIT);
+ store_constructor (exp, to_rtx, 0, bitsize / BITS_PER_UNIT, reverse);
return to_rtx;
}
- return store_expr (exp, to_rtx, 0, nontemporal);
+ return store_expr (exp, to_rtx, 0, nontemporal, reverse);
}
}
@@ -6747,7 +6801,8 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
codes and find the ultimate containing object, which we return.
We set *PBITSIZE to the size in bits that we want, *PBITPOS to the
- bit position, and *PUNSIGNEDP to the signedness of the field.
+ bit position, *PUNSIGNEDP to the signedness and *PREVERSEP to the
+ storage order of the field.
If the position of the field is variable, we store a tree
giving the variable offset (in units) in *POFFSET.
This offset is in addition to the bit position.
@@ -6781,7 +6836,7 @@ tree
get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
HOST_WIDE_INT *pbitpos, tree *poffset,
machine_mode *pmode, int *punsignedp,
- int *pvolatilep, bool keep_aligning)
+ int *preversep, int *pvolatilep, bool keep_aligning)
{
tree size_tree = 0;
machine_mode mode = VOIDmode;
@@ -6789,8 +6844,8 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
tree offset = size_zero_node;
offset_int bit_offset = 0;
- /* First get the mode, signedness, and size. We do this from just the
- outermost expression. */
+ /* First get the mode, signedness, storage order and size. We do this from
+ just the outermost expression. */
*pbitsize = -1;
if (TREE_CODE (exp) == COMPONENT_REF)
{
@@ -6843,6 +6898,8 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
*pbitsize = tree_to_uhwi (size_tree);
}
+ *preversep = reverse_storage_order_for_component_p (exp);
+
/* Compute cumulative bit-offset for nested component-refs and array-refs,
and find the ultimate containing object. */
while (1)
@@ -7519,7 +7576,7 @@ expand_expr_addr_expr_1 (tree exp, rtx target, machine_mode tmode,
rtx result, subtarget;
tree inner, offset;
HOST_WIDE_INT bitsize, bitpos;
- int volatilep, unsignedp;
+ int unsignedp, reversep, volatilep = 0;
machine_mode mode1;
/* If we are taking the address of a constant and are at the top level,
@@ -7626,8 +7683,8 @@ expand_expr_addr_expr_1 (tree exp, rtx target, machine_mode tmode,
handle "aligning nodes" here: we can just bypass them because
they won't change the final object whose address will be returned
(they actually exist only for that purpose). */
- inner = get_inner_reference (exp, &bitsize, &bitpos, &offset,
- &mode1, &unsignedp, &volatilep, false);
+ inner = get_inner_reference (exp, &bitsize, &bitpos, &offset, &mode1,
+ &unsignedp, &reversep, &volatilep, false);
break;
}
@@ -7811,7 +7868,7 @@ expand_constructor (tree exp, rtx target, enum expand_modifier modifier,
target = assign_temp (type, TREE_ADDRESSABLE (exp), 1);
}
- store_constructor (exp, target, 0, int_expr_size (exp));
+ store_constructor (exp, target, 0, int_expr_size (exp), false);
return target;
}
@@ -8084,11 +8141,12 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
store_expr (treeop0,
adjust_address (target, TYPE_MODE (valtype), 0),
modifier == EXPAND_STACK_PARM,
- false);
+ false, TYPE_REVERSE_STORAGE_ORDER (type));
else
{
- gcc_assert (REG_P (target));
+ gcc_assert (REG_P (target)
+ && !TYPE_REVERSE_STORAGE_ORDER (type));
/* Store this field into a union of the proper type. */
store_field (target,
@@ -8096,7 +8154,8 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
(treeop0))
* BITS_PER_UNIT),
(HOST_WIDE_INT) GET_MODE_BITSIZE (mode)),
- 0, 0, 0, TYPE_MODE (valtype), treeop0, 0, false);
+ 0, 0, 0, TYPE_MODE (valtype), treeop0, 0,
+ false, false);
}
/* Return the entire union. */
@@ -9131,7 +9190,7 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
int index = BYTES_BIG_ENDIAN ? GET_MODE_NUNITS (vec_mode) - 1 : 0;
int bitsize = GET_MODE_UNIT_BITSIZE (vec_mode);
temp = extract_bit_field (temp, bitsize, bitsize * index, unsignedp,
- target, mode, mode);
+ target, mode, mode, false);
gcc_assert (temp);
return temp;
}
@@ -9287,14 +9346,14 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
jumpifnot (treeop0, lab0, -1);
store_expr (treeop1, temp,
modifier == EXPAND_STACK_PARM,
- false);
+ false, false);
emit_jump_insn (targetm.gen_jump (lab1));
emit_barrier ();
emit_label (lab0);
store_expr (treeop2, temp,
modifier == EXPAND_STACK_PARM,
- false);
+ false, false);
emit_label (lab1);
OK_DEFER_POP;
@@ -9847,6 +9906,7 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
case MEM_REF:
{
+ const bool reverse = REF_REVERSE_STORAGE_ORDER (exp);
addr_space_t as
= TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))));
machine_mode address_mode;
@@ -9861,6 +9921,7 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
HOST_WIDE_INT offset = mem_ref_offset (exp).to_short_addr ();
base = TREE_OPERAND (base, 0);
if (offset == 0
+ && !reverse
&& tree_fits_uhwi_p (TYPE_SIZE (type))
&& (GET_MODE_BITSIZE (DECL_MODE (base))
== tree_to_uhwi (TYPE_SIZE (type))))
@@ -9870,13 +9931,14 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
{
temp = assign_stack_temp (DECL_MODE (base),
GET_MODE_SIZE (DECL_MODE (base)));
- store_expr (base, temp, 0, false);
+ store_expr (base, temp, 0, false, false);
temp = adjust_address (temp, BLKmode, offset);
set_mem_size (temp, int_size_in_bytes (type));
return temp;
}
exp = build3 (BIT_FIELD_REF, type, base, TYPE_SIZE (type),
bitsize_int (offset * BITS_PER_UNIT));
+ REF_REVERSE_STORAGE_ORDER (exp) = reverse;
return expand_expr (exp, target, tmode, modifier);
}
address_mode = targetm.addr_space.address_mode (as);
@@ -9926,8 +9988,12 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
0, TYPE_UNSIGNED (TREE_TYPE (exp)),
(modifier == EXPAND_STACK_PARM
? NULL_RTX : target),
- mode, mode);
+ mode, mode, false);
}
+ if (reverse
+ && modifier != EXPAND_MEMORY
+ && modifier != EXPAND_WRITE)
+ temp = flip_storage_order (mode, temp);
return temp;
}
@@ -10133,9 +10199,10 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
machine_mode mode1, mode2;
HOST_WIDE_INT bitsize, bitpos;
tree offset;
- int volatilep = 0, must_force_mem;
- tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
- &mode1, &unsignedp, &volatilep, true);
+ int reversep, volatilep = 0, must_force_mem;
+ tree tem
+ = get_inner_reference (exp, &bitsize, &bitpos, &offset, &mode1,
+ &unsignedp, &reversep, &volatilep, true);
rtx orig_op0, memloc;
bool clear_mem_expr = false;
@@ -10190,7 +10257,11 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
{
if (bitpos == 0
&& bitsize == GET_MODE_BITSIZE (GET_MODE (op0)))
- return op0;
+ {
+ if (reversep)
+ op0 = flip_storage_order (GET_MODE (op0), op0);
+ return op0;
+ }
if (bitpos == 0
&& bitsize == GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 0)))
&& bitsize)
@@ -10376,20 +10447,38 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
if (MEM_P (op0) && REG_P (XEXP (op0, 0)))
mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
+ /* If the result has a record type and the extraction is done in
+ an integral mode, then the field may be not aligned on a byte
+ boundary; in this case, if it has reverse storage order, it
+ needs to be extracted as a scalar field with reverse storage
+ order and put back into memory order afterwards. */
+ if (TREE_CODE (type) == RECORD_TYPE
+ && GET_MODE_CLASS (ext_mode) == MODE_INT)
+ reversep = TYPE_REVERSE_STORAGE_ORDER (type);
+
op0 = extract_bit_field (op0, bitsize, bitpos, unsignedp,
(modifier == EXPAND_STACK_PARM
? NULL_RTX : target),
- ext_mode, ext_mode);
-
- /* If the result is a record type and BITSIZE is narrower than
- the mode of OP0, an integral mode, and this is a big endian
- machine, we must put the field into the high-order bits. */
- if (TREE_CODE (type) == RECORD_TYPE && BYTES_BIG_ENDIAN
- && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
- && bitsize < (HOST_WIDE_INT) GET_MODE_BITSIZE (GET_MODE (op0)))
- op0 = expand_shift (LSHIFT_EXPR, GET_MODE (op0), op0,
- GET_MODE_BITSIZE (GET_MODE (op0))
- - bitsize, op0, 1);
+ ext_mode, ext_mode, reversep);
+
+ /* If the result has a record type and the mode of OP0 is an
+ integral mode then, if BITSIZE is narrower than this mode
+ and this is for big-endian data, we must put the field
+ into the high-order bits. And we must also put it back
+ into memory order if it has been previously reversed. */
+ if (TREE_CODE (type) == RECORD_TYPE
+ && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT)
+ {
+ HOST_WIDE_INT size = GET_MODE_BITSIZE (GET_MODE (op0));
+
+ if (bitsize < size
+ && reversep ? !BYTES_BIG_ENDIAN : BYTES_BIG_ENDIAN)
+ op0 = expand_shift (LSHIFT_EXPR, GET_MODE (op0), op0,
+ size - bitsize, op0, 1);
+
+ if (reversep)
+ op0 = flip_storage_order (GET_MODE (op0), op0);
+ }
/* If the result type is BLKmode, store the data into a temporary
of the appropriate type, but with the mode corresponding to the
@@ -10435,6 +10524,12 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
set_mem_expr (op0, NULL_TREE);
MEM_VOLATILE_P (op0) |= volatilep;
+
+ if (reversep
+ && modifier != EXPAND_MEMORY
+ && modifier != EXPAND_WRITE)
+ op0 = flip_storage_order (mode1, op0);
+
if (mode == mode1 || mode1 == BLKmode || mode1 == tmode
|| modifier == EXPAND_CONST_ADDRESS
|| modifier == EXPAND_INITIALIZER)
@@ -10498,17 +10593,16 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
machine_mode mode1;
HOST_WIDE_INT bitsize, bitpos;
tree offset;
- int unsignedp;
- int volatilep = 0;
+ int unsignedp, reversep, volatilep = 0;
tree tem
- = get_inner_reference (treeop0, &bitsize, &bitpos,
- &offset, &mode1, &unsignedp, &volatilep,
- true);
+ = get_inner_reference (treeop0, &bitsize, &bitpos, &offset, &mode1,
+ &unsignedp, &reversep, &volatilep, true);
rtx orig_op0;
/* ??? We should work harder and deal with non-zero offsets. */
if (!offset
&& (bitpos % BITS_PER_UNIT) == 0
+ && !reversep
&& bitsize >= 0
&& compare_tree_int (TYPE_SIZE (type), bitsize) == 0)
{
@@ -10582,7 +10676,7 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
else if (reduce_bit_field)
return extract_bit_field (op0, TYPE_PRECISION (type), 0,
TYPE_UNSIGNED (type), NULL_RTX,
- mode, mode);
+ mode, mode, false);
/* As a last resort, spill op0 to memory, and reload it in a
different mode. */
else if (!MEM_P (op0))