#define choices \
this_target_lower_subreg->x_choices
+/* Return true if MODE is a mode we know how to lower. When returning true,
+ store its byte size in *BYTES and its word size in *WORDS. */
+
+static inline bool
+interesting_mode_p (machine_mode mode, unsigned int *bytes,
+ unsigned int *words)
+{
+ *bytes = GET_MODE_SIZE (mode);
+ *words = CEIL (*bytes, UNITS_PER_WORD);
+ return true;
+}
+
/* RTXes used while computing costs. */
struct cost_rtxes {
/* Source and target registers. */
for (i = 0; i < MAX_MACHINE_MODE; i++)
{
machine_mode mode = (machine_mode) i;
- int factor = GET_MODE_SIZE (mode) / UNITS_PER_WORD;
- if (factor > 1)
+ unsigned int size, factor;
+ if (interesting_mode_p (mode, &size, &factor) && factor > 1)
{
- int mode_move_cost;
+ unsigned int mode_move_cost;
PUT_MODE (rtxes->target, mode);
PUT_MODE (rtxes->source, mode);
continue;
}
- outer_size = GET_MODE_SIZE (GET_MODE (x));
- inner_size = GET_MODE_SIZE (GET_MODE (inner));
- outer_words = (outer_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
- inner_words = (inner_size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+ if (!interesting_mode_p (GET_MODE (x), &outer_size, &outer_words)
+ || !interesting_mode_p (GET_MODE (inner), &inner_size,
+ &inner_words))
+ continue;
/* We only try to decompose single word subregs of multi-word
registers. When we find one, we return -1 to avoid iterating
}
else if (REG_P (x))
{
- unsigned int regno;
+ unsigned int regno, size, words;
/* We will see an outer SUBREG before we see the inner REG, so
when we see a plain REG here it means a direct reference to
regno = REGNO (x);
if (!HARD_REGISTER_NUM_P (regno)
- && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
+ && interesting_mode_p (GET_MODE (x), &size, &words)
+ && words > 1)
{
switch (*pcmi)
{
decompose_register (unsigned int regno)
{
rtx reg;
- unsigned int words, i;
+ unsigned int size, words, i;
rtvec v;
reg = regno_reg_rtx[regno];
regno_reg_rtx[regno] = NULL_RTX;
- words = GET_MODE_SIZE (GET_MODE (reg));
- words = (words + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+ if (!interesting_mode_p (GET_MODE (reg), &size, &words))
+ gcc_unreachable ();
v = rtvec_alloc (words);
for (i = 0; i < words; ++i)
simplify_subreg_concatn (machine_mode outermode, rtx op,
unsigned int byte)
{
- unsigned int inner_size;
+ unsigned int outer_size, outer_words, inner_size, inner_words;
machine_mode innermode, partmode;
rtx part;
unsigned int final_offset;
+ innermode = GET_MODE (op);
+ if (!interesting_mode_p (outermode, &outer_size, &outer_words)
+ || !interesting_mode_p (innermode, &inner_size, &inner_words))
+ gcc_unreachable ();
+
gcc_assert (GET_CODE (op) == CONCATN);
- gcc_assert (byte % GET_MODE_SIZE (outermode) == 0);
+ gcc_assert (byte % outer_size == 0);
- innermode = GET_MODE (op);
- gcc_assert (byte < GET_MODE_SIZE (innermode));
- if (GET_MODE_SIZE (outermode) > GET_MODE_SIZE (innermode))
+ gcc_assert (byte < inner_size);
+ if (outer_size > inner_size)
return NULL_RTX;
- inner_size = GET_MODE_SIZE (innermode) / XVECLEN (op, 0);
+ inner_size /= XVECLEN (op, 0);
part = XVECEXP (op, 0, byte / inner_size);
partmode = GET_MODE (part);
final_offset = byte % inner_size;
- if (final_offset + GET_MODE_SIZE (outermode) > inner_size)
+ if (final_offset + outer_size > inner_size)
return NULL_RTX;
/* VECTOR_CSTs in debug expressions are expanded into CONCATN instead of
if (HARD_REGISTER_NUM_P (regno))
{
- unsigned int byte, num_bytes;
+ unsigned int byte, num_bytes, num_words;
- num_bytes = GET_MODE_SIZE (GET_MODE (x));
+ if (!interesting_mode_p (GET_MODE (x), &num_bytes, &num_words))
+ return false;
for (byte = 0; byte < num_bytes; byte += UNITS_PER_WORD)
if (simplify_subreg_regno (regno, GET_MODE (x), byte, word_mode) < 0)
return false;
rtx src, dest, real_dest;
rtx_insn *insns;
machine_mode orig_mode, dest_mode;
- unsigned int words;
+ unsigned int orig_size, words;
bool pushing;
src = SET_SRC (set);
dest = SET_DEST (set);
orig_mode = GET_MODE (dest);
- words = (GET_MODE_SIZE (orig_mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+ if (!interesting_mode_p (orig_mode, &orig_size, &words))
+ gcc_unreachable ();
gcc_assert (words > 1);
start_sequence ();
{
unsigned int i, j, jinc;
- gcc_assert (GET_MODE_SIZE (orig_mode) % UNITS_PER_WORD == 0);
+ gcc_assert (orig_size % UNITS_PER_WORD == 0);
gcc_assert (GET_CODE (XEXP (dest, 0)) != PRE_MODIFY);
gcc_assert (GET_CODE (XEXP (dest, 0)) != POST_MODIFY);
{
rtx reg;
machine_mode orig_mode;
- unsigned int words, i;
+ unsigned int orig_size, words, i;
int ret;
reg = XEXP (pat, 0);
return false;
orig_mode = GET_MODE (reg);
- words = GET_MODE_SIZE (orig_mode);
- words = (words + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+ if (!interesting_mode_p (orig_mode, &orig_size, &words))
+ gcc_unreachable ();
ret = validate_change (NULL_RTX, &XEXP (pat, 0),
simplify_gen_subreg_concatn (word_mode, reg,
static void
dump_choices (bool speed_p, const char *description)
{
- unsigned int i;
+ unsigned int size, factor, i;
fprintf (dump_file, "Choices when optimizing for %s:\n", description);
for (i = 0; i < MAX_MACHINE_MODE; i++)
- if (GET_MODE_SIZE ((machine_mode) i) > UNITS_PER_WORD)
+ if (interesting_mode_p ((machine_mode) i, &size, &factor)
+ && factor > 1)
fprintf (dump_file, " %s mode %s for copy lowering.\n",
choices[speed_p].move_modes_to_split[i]
? "Splitting"