https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119966

--- Comment #6 from Richard Sandiford <rsandifo at gcc dot gnu.org> ---
(In reply to Andrew Pinski from comment #4)
> validate_subreg allows the paradoxical subreg even in the case of hard
> register:
> ```
>   /* Paradoxical subregs must have offset zero.  */
>   if (maybe_gt (osize, isize))
>     return known_eq (offset, 0U);
> 
>   /* This is a normal subreg.  Verify that the offset is representable.  */
> 
>   /* For hard registers, we already have most of these rules collected in
>      subreg_offset_representable_p.  */
>   if (reg && REG_P (reg) && HARD_REGISTER_P (reg))
> ...
> 
> So either validate_subreg needs to reject if the subreg of a hard reg is not
> valid for that mode for paradoxical subreg.
Yeah, I think the check that paradoxical subregs have offset 0 should be
return-if-false-continue-if-true test, like the others.

  /* The outer size must be ordered wrt the register size, otherwise
     we wouldn't know at compile time how many registers the outer
     mode occupies.  */
  if (!ordered_p (osize, regsize))
    return false;

is also potentially relevant.  But we would have to skip:

  /* For pseudo registers, we want most of the same checks.  Namely:

     Assume that the pseudo register will be allocated to hard registers
     that can hold REGSIZE bytes each.  If OSIZE is not a multiple of REGSIZE,
     the remainder must correspond to the lowpart of the containing hard
     register.  If BYTES_BIG_ENDIAN, the lowpart is at the highest offset,
     otherwise it is at the lowest offset.

     Given that we've already checked the mode and offset alignment,
     we only have to check subblock subregs here.  */
  if (maybe_lt (osize, regsize)
      && ! (lra_in_progress && (FLOAT_MODE_P (imode) || FLOAT_MODE_P (omode))))
    {
      /* It is invalid for the target to pick a register size for a mode
         that isn't ordered wrt to the size of that mode.  */
      poly_uint64 block_size = ordered_min (isize, regsize);
      unsigned int start_reg;
      poly_uint64 offset_within_reg;
      if (!can_div_trunc_p (offset, block_size, &start_reg, &offset_within_reg)
          || (BYTES_BIG_ENDIAN
              ? maybe_ne (offset_within_reg, block_size - osize)
              : maybe_ne (offset_within_reg, 0U)))
        return false;
    }

because the BYTES_BIG_ENDIAN test would fail for paradoxical subregs.

Reply via email to