bool
truncated_to_mode (enum machine_mode mode, rtx x)
{
if (REG_P (x) && rtl_hooks.reg_truncated_to_mode (mode, x))
return true;
gcc_assert (!TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
GET_MODE_BITSIZE (GET_MODE (x)));
return num_sign_bit_copies (x, GET_MODE (x)) >
GET_MODE_BITSIZE (GET_MODE (x)) - GET_MODE_BITSIZE (mode);
}
In the MIPS case, you would have n_s_b_c (x, GET_MODE (x)) > 64 - 32.
This wouldn't work for DI->HI truncation for example. There too only
the upper 33 bits have to match for the TRUNCATE to be unnecessary.
See comment around truncsdi in mips.md.
If this is so, SImode should be passed to reg_truncated_to_mode as well,
instead of HImode, shouldn't it? What about this logic:
int n = num_sign_bit_copies (x, GET_MODE (x));
int dest_bits;
enum machine_mode next_mode = mode;
do
{
mode = next_mode;
dest_bits = GET_MODE_BITSIZE (mode);
/* If it is a no-op to truncate to MODE from a wider mode (e.g. to
HI from SI on MIPS),
we can check a weaker condition. */
next_mode = GET_MODE_WIDER_MODE (mode);
}
while (next_mode != VOIDmode
&& TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (next_mode),
dest_bits);
return (REG_P (x) && rtl_hooks.reg_truncated_to_mode (mode, x))
|| n > GET_MODE_BITSIZE (GET_MODE (x)) - dest_bits);
On MIPS, we would not test HImode but SImode since TRULY_NOOP_TRUNCATION
(32, 16) == true. To me, this is a clue that the TRULY_NOOP_TRUNCATION
macro is insufficient and could be replaced by another one. For example
(for MIPS -- SHmedia is the same with s/MIPS64/SHMEDIA/):
/* Return the mode to which we should truncate an INMODE value before
operating
on it in OUTMODE. For example, on MIPS we should truncate a 64-bit value
to 32-bits when operating on it in SImode or a narrower mode.
We return INMODE if no such truncation is necessary and we can just
pretend
that the value is already truncated. */
#define WIDEST_NECESSARY_TRUNCATION(outmode, inmode) \
(TARGET_MIPS64 \
&& GET_MODE_BITSIZE (inmode) <= 32 \
&& GET_MODE_BITSIZE (outmode) > 32 ? SImode : inmode)
Since all uses of TRULY_NOOP_TRUNCATION (except one in convert.c which
could be changed to use TYPE_MODE) are of the form TRULY_NOOP_TRUNCATION
(GET_MODE_BITSIZE (x), GET_MODE_BITSIZE (y)), you could change them to
WIDEST_NECESSARY_TRUNCATION (x, y) != y
We could also take the occasion to remove all the defines of
TRULY_NOOP_TRUNCATION to 1, and put a default definition in defaults.h!
You can then proceed to implement truncated_to_mode as
mode = WIDEST_NECESSARY_TRUNCATION (mode, GET_MODE (x));
gcc_assert (mode != GET_MODE (x));
return (REG_P (x) && rtl_hooks.reg_truncated_to_mode (mode, x))
|| num_sign_bit_copies (x, GET_MODE (x)) >
GET_MODE_BITSIZE (GET_MODE (x)) - GET_MODE_BITSIZE (mode);
What do you think?
Paolo