@@ -2215,6 +2215,10 @@ should give the natural size in bytes for the specified mode. It is
used by the register allocator to try to optimize its results. This
happens for example on SPARC 64-bit where the natural size of
floating-point registers is still 32-bit.
+
+If a target specifies @code{REGMODE_NATURAL_SIZE}, it must provide
+move patterns for all scalar integer modes no larger than the
+largest @code{REGMODE_NATURAL_SIZE}.
@end defmac
@deftypefn {Target Hook} bool TARGET_HARD_REGNO_MODE_OK (unsigned int @var{regno}, machine_mode @var{mode})
@@ -1878,6 +1878,10 @@ should give the natural size in bytes for the specified mode. It is
used by the register allocator to try to optimize its results. This
happens for example on SPARC 64-bit where the natural size of
floating-point registers is still 32-bit.
+
+If a target specifies @code{REGMODE_NATURAL_SIZE}, it must provide
+move patterns for all scalar integer modes no larger than the
+largest @code{REGMODE_NATURAL_SIZE}.
@end defmac
@hook TARGET_HARD_REGNO_MODE_OK
@@ -865,12 +865,16 @@ store_bit_field_1 (rtx str_rtx, poly_uint64 bitsize, poly_uint64 bitnum,
valid for integral modes. */
opt_scalar_int_mode op0_mode = int_mode_for_mode (GET_MODE (op0));
scalar_int_mode imode;
+ bool need_stack_p = false;
if (!op0_mode.exists (&imode) || imode != GET_MODE (op0))
{
if (MEM_P (op0))
op0 = adjust_bitfield_address_size (op0, op0_mode.else_blk (),
0, MEM_SIZE (op0));
- else if (!op0_mode.exists ())
+ else if (!op0_mode.exists ()
+ || maybe_lt
+ ((unsigned) UNITS_PER_WORD,
+ (poly_uint64) REGMODE_NATURAL_SIZE (GET_MODE (op0))))
{
if (ibitnum == 0
&& known_eq (ibitsize, GET_MODE_BITSIZE (GET_MODE (op0)))
@@ -883,17 +887,29 @@ store_bit_field_1 (rtx str_rtx, poly_uint64 bitsize, poly_uint64 bitnum,
}
if (!fallback_p)
return false;
- rtx temp = assign_stack_temp (GET_MODE (op0),
- GET_MODE_SIZE (GET_MODE (op0)));
- emit_move_insn (temp, op0);
- store_bit_field_1 (temp, bitsize, bitnum, 0, 0, fieldmode, value,
- reverse, fallback_p, undefined_p);
- emit_move_insn (op0, temp);
- return true;
+ need_stack_p = true;
}
else
op0 = gen_lowpart (op0_mode.require (), op0);
}
+ else if (!MEM_P (op0)
+ && maybe_lt ((unsigned) UNITS_PER_WORD,
+ (poly_uint64) REGMODE_NATURAL_SIZE (GET_MODE (op0))))
+ need_stack_p = true;
+
+ /* With or without punning we might be faced with a mode that we cannot
+ split into words. If so, spill OP0 to the stack and recurse.
+ This happens at most once. */
+ if (need_stack_p)
+ {
+ rtx temp = assign_stack_temp (GET_MODE (op0),
+ GET_MODE_SIZE (GET_MODE (op0)));
+ emit_move_insn (temp, op0);
+ store_bit_field_1 (temp, bitsize, bitnum, 0, 0, fieldmode, value,
+ reverse, fallback_p, undefined_p);
+ emit_move_insn (op0, temp);
+ return true;
+ }
return store_integral_bit_field (op0, op0_mode, ibitsize, ibitnum,
bitregion_start, bitregion_end,
@@ -1015,7 +1031,9 @@ store_integral_bit_field (rtx op0, opt_scalar_int_mode op0_mode,
in BLKmode to handle unaligned memory references and to shift the
last chunk right on big-endian machines if need be. */
rtx value_word
- = fieldmode == BLKmode
+ = (fieldmode == BLKmode
+ || maybe_lt ((unsigned) UNITS_PER_WORD,
+ (poly_uint64) REGMODE_NATURAL_SIZE (value_mode)))
? extract_bit_field (value, new_bitsize, wordnum * BITS_PER_WORD,
1, NULL_RTX, word_mode, word_mode, false,
NULL)
@@ -1851,12 +1869,16 @@ extract_bit_field_1 (rtx str_rtx, poly_uint64 bitsize, poly_uint64 bitnum,
if we aren't. */
opt_scalar_int_mode op0_mode = int_mode_for_mode (GET_MODE (op0));
scalar_int_mode imode;
+ bool need_stack_p = false;
if (!op0_mode.exists (&imode) || imode != GET_MODE (op0))
{
if (MEM_P (op0))
op0 = adjust_bitfield_address_size (op0, op0_mode.else_blk (),
0, MEM_SIZE (op0));
- else if (op0_mode.exists (&imode))
+ else if (op0_mode.exists (&imode)
+ && known_ge
+ ((unsigned) UNITS_PER_WORD,
+ (poly_uint64) REGMODE_NATURAL_SIZE (GET_MODE (op0))))
{
op0 = gen_lowpart (imode, op0);
@@ -1866,12 +1888,19 @@ extract_bit_field_1 (rtx str_rtx, poly_uint64 bitsize, poly_uint64 bitnum,
op0 = force_reg (imode, op0);
}
else
- {
- poly_int64 size = GET_MODE_SIZE (GET_MODE (op0));
- rtx mem = assign_stack_temp (GET_MODE (op0), size);
- emit_move_insn (mem, op0);
- op0 = adjust_bitfield_address_size (mem, BLKmode, 0, size);
- }
+ need_stack_p = true;
+ }
+ else if (!MEM_P (op0)
+ && maybe_lt ((unsigned) UNITS_PER_WORD,
+ (poly_uint64) REGMODE_NATURAL_SIZE (GET_MODE (op0))))
+ need_stack_p = true;
+
+ if (need_stack_p)
+ {
+ poly_int64 size = GET_MODE_SIZE (GET_MODE (op0));
+ rtx mem = assign_stack_temp (GET_MODE (op0), size);
+ emit_move_insn (mem, op0);
+ op0 = adjust_bitfield_address_size (mem, BLKmode, 0, size);
}
/* ??? We currently assume TARGET is at least as big as BITSIZE.
@@ -4199,9 +4199,6 @@ read_complex_part (rtx cplx, bool imag_p)
imag_p ? GET_MODE_SIZE (imode) : 0);
if (ret)
return ret;
- else
- /* simplify_gen_subreg may fail for sub-word MEMs. */
- gcc_assert (MEM_P (cplx) && ibitsize < BITS_PER_WORD);
}
return extract_bit_field (cplx, ibitsize, imag_p ? ibitsize : 0,
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see
#include "memmodel.h"
#include "tm_p.h"
#include "expmed.h"
+#include "regs.h"
#include "insn-config.h"
#include "emit-rtl.h"
#include "recog.h"
@@ -113,6 +114,9 @@ interesting_mode_p (machine_mode mode, unsigned int *bytes,
{
if (!GET_MODE_SIZE (mode).is_constant (bytes))
return false;
+ if (maybe_lt ((unsigned) UNITS_PER_WORD,
+ (poly_uint64) REGMODE_NATURAL_SIZE (mode)))
+ return false;
*words = CEIL (*bytes, UNITS_PER_WORD);
return true;
}
@@ -302,7 +306,20 @@ static bool
simple_move_operand (rtx x)
{
if (GET_CODE (x) == SUBREG)
- x = SUBREG_REG (x);
+ {
+ /* Exclude subregs whose outer mode can be split into multiple words
+ but whose inner mode cannot. Attempting to split such a subreg
+ would mean trying to split the unsplittable inner register.
+
+ If instead the subreg occupies a single word, we can keep it as-is,
+ regardless of what the SUBREG_REG is. If the outer mode cannot be
+ split then the subreg makes things no worse than they already are. */
+ unsigned int factor, size;
+ if (interesting_mode_p (GET_MODE (x), &size, &factor) && factor > 1
+ && !interesting_mode_p (GET_MODE (SUBREG_REG (x)), &size, &factor))
+ return false;
+ x = SUBREG_REG (x);
+ }
if (!OBJECT_P (x))
return false;
@@ -649,18 +666,21 @@ decompose_register (unsigned int regno)
static rtx
simplify_subreg_concatn (machine_mode outermode, rtx op, poly_uint64 orig_byte)
{
- unsigned int outer_size, outer_words, inner_size, inner_words;
+ unsigned int outer_size, inner_size, inner_words;
machine_mode innermode, partmode;
rtx part;
unsigned int final_offset;
unsigned int byte;
innermode = GET_MODE (op);
- if (!interesting_mode_p (outermode, &outer_size, &outer_words)
- || !interesting_mode_p (innermode, &inner_size, &inner_words))
+
+ if (!interesting_mode_p (innermode, &inner_size, &inner_words))
gcc_unreachable ();
- /* Must be constant if interesting_mode_p passes. */
+ if (!GET_MODE_SIZE (outermode).is_constant (&outer_size))
+ return NULL_RTX;
+
+ /* Must be constant if outer_size is. */
byte = orig_byte.to_constant ();
gcc_assert (GET_CODE (op) == CONCATN);
gcc_assert (byte % outer_size == 0);