Hi,

when looking at a riscv ICE in vect-live-6.c I noticed that we
assume that the variable part (coeffs[1] * x1) of the to-be-extracted
bit number in extract_bit_field_1 is a multiple of BITS_PER_UNIT.

This means that bits_to_bytes_round_down and num_trailing_bits
cannot handle e.g. extracting from a "VNx4BI"-mode vector which has
4-bit precision on riscv.

This patch adds a special case for that situation and sets bytenum to
zero as well as bitnum to its proper value.  It works for the riscv
case because in all other situations we can align to a byte boundary.
If x1 were 3 for some reason, however, the above assertion would still
fail.  I don't think this can happen for riscv as we only ever double
the number of chunks for larger vector sizes but not sure about the
general case.

If there's another, correct way to work around feel free to suggest.

Bootstrap/testsuite on aarch64 and x86 is running but I would be
surprised if there were any changes as riscv is the only target that
uses modes with precision < 8.

Regards
 Robin

gcc/ChangeLog:

        * expmed.cc (extract_bit_field_1): Handle bitnum with variable
        part less than BITS_PER_UNIT.
---
 gcc/expmed.cc | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/gcc/expmed.cc b/gcc/expmed.cc
index e22e43c8505..1b0119f9cfc 100644
--- a/gcc/expmed.cc
+++ b/gcc/expmed.cc
@@ -1858,8 +1858,22 @@ extract_bit_field_1 (rtx str_rtx, poly_uint64 bitsize, 
poly_uint64 bitnum,
      but is useful for things like vector booleans.  */
   if (MEM_P (op0) && !bitnum.is_constant ())
     {
-      bytenum = bits_to_bytes_round_down (bitnum);
-      bitnum = num_trailing_bits (bitnum);
+      /* bits_to_bytes_round_down tries to align to a byte (BITS_PER_UNIT)
+        boundary and asserts that bitnum.coeffs[1] % BITS_PER_UNIT == 0.
+        For modes with precision < BITS_PER_UNIT this fails but we can
+        still extract from the first byte.  */
+      poly_uint16 prec = GET_MODE_PRECISION (outermode);
+      if (prec.coeffs[1] < BITS_PER_UNIT && bitnum.coeffs[1] < BITS_PER_UNIT)
+       {
+         bytenum = 0;
+         bitnum = bitnum.coeffs[0] & (BITS_PER_UNIT - 1);
+       }
+      else
+       {
+         bytenum = bits_to_bytes_round_down (bitnum);
+         bitnum = num_trailing_bits (bitnum);
+       }
+
       poly_uint64 bytesize = bits_to_bytes_round_up (bitnum + bitsize);
       op0 = adjust_bitfield_address_size (op0, BLKmode, bytenum, bytesize);
       op0_mode = opt_scalar_int_mode ();
-- 
2.41.0

Reply via email to