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

Richard Biener <rguenth at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Assignee|unassigned at gcc dot gnu.org      |rguenth at gcc dot 
gnu.org
             Status|NEW                         |ASSIGNED

--- Comment #3 from Richard Biener <rguenth at gcc dot gnu.org> ---
The subreg is generated from store_bit_field_1:

#10 0x0000000001224f12 in store_bit_field (str_rtx=0x7ffff6720fc0, 
    bitsize=..., bitnum=..., bitregion_start=..., bitregion_end=..., 
    fieldmode=E_OImode, value=0x7ffff63490a8, reverse=false)
    at /home/rguenther/src/gcc3/gcc/expmed.c:1186
...
  /* If the target is a register, overwriting the entire object, or storing
     a full-word or multi-word field can be done with just a SUBREG.  */
  if (!MEM_P (op0)
      && known_eq (bitsize, GET_MODE_BITSIZE (fieldmode)))
    {

but note how fieldmode is OImode while op0 is (reg:TI 84 [ buffer ]).

it goes on

      /* Use the subreg machinery either to narrow OP0 to the required
         words or to cope with mode punning between equal-sized modes.
         In the latter case, use subreg on the rhs side, not lhs.  */
      rtx sub;
      HOST_WIDE_INT regnum;
      poly_uint64 regsize = REGMODE_NATURAL_SIZE (GET_MODE (op0));
      if (known_eq (bitnum, 0U)
          && known_eq (bitsize, GET_MODE_BITSIZE (GET_MODE (op0))))
        {
          sub = simplify_gen_subreg (GET_MODE (op0), value, fieldmode, 0);
          if (sub)
            {
              if (reverse)
                sub = flip_storage_order (GET_MODE (op0), sub);
              emit_move_insn (op0, sub);
              return true;
            }
        }

it doesn't mention the widening of the LHS, but

      else if (constant_multiple_p (bitnum, regsize * BITS_PER_UNIT, &regnum)
               && multiple_p (bitsize, regsize * BITS_PER_UNIT))
        {
          sub = simplify_gen_subreg (fieldmode, op0, GET_MODE (op0),
                                     regnum * regsize);
          if (sub)
            {
              if (reverse)
                value = flip_storage_order (fieldmode, value);
              emit_move_insn (sub, value);
              return true;
            }
        }

this does just this.  So eventually the known_eq in the first case can
be changed to known_ge in which case we no longer ICE but prune the RHS.

diff --git a/gcc/expmed.c b/gcc/expmed.c
index 59734d4841c..0e8a60245aa 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -788,13 +788,14 @@ store_bit_field_1 (rtx str_rtx, poly_uint64 bitsize,
poly_uint64 bitnum,
       && known_eq (bitsize, GET_MODE_BITSIZE (fieldmode)))
     {
       /* Use the subreg machinery either to narrow OP0 to the required
-        words or to cope with mode punning between equal-sized modes.
-        In the latter case, use subreg on the rhs side, not lhs.  */
+        words or to cope with mode punning between equal-sized modes
+        or storage of excess bytes.  In the latter case, use subreg on
+        the rhs side, not lhs.  */
       rtx sub;
       HOST_WIDE_INT regnum;
       poly_uint64 regsize = REGMODE_NATURAL_SIZE (GET_MODE (op0));
       if (known_eq (bitnum, 0U)
-         && known_eq (bitsize, GET_MODE_BITSIZE (GET_MODE (op0))))
+         && known_ge (bitsize, GET_MODE_BITSIZE (GET_MODE (op0))))
        {
          sub = simplify_gen_subreg (GET_MODE (op0), value, fieldmode, 0);
          if (sub)


another possibility is to fix the condition on the case we run into:

@@ -806,7 +807,7 @@ store_bit_field_1 (rtx str_rtx, poly_uint64 bitsize,
poly_uint64 bitnum,
            }
        }
       else if (constant_multiple_p (bitnum, regsize * BITS_PER_UNIT, &regnum)
-              && multiple_p (bitsize, regsize * BITS_PER_UNIT))
+              && multiple_p (regsize * BITS_PER_UNIT, bitsize))
        {
          sub = simplify_gen_subreg (fieldmode, op0, GET_MODE (op0),
                                     regnum * regsize);

Reply via email to