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

Reply via email to