> One thing to do is to call simplify_gen_subreg.  I don't know why this
> code still calls gen_rtx_SUBREG.  It's pretty old code.
> 
> But I don't think that will help.  I think this code is simply
> incorrect.  It seems to assume that op_mode is at least as large as
> GET_MODE (xop0), probably because that will be the case on the m68k.

How about something like this?  It calls simplify_gen_subreg() but
uses the return value to determine if the overall attempt (that "if"
clause) should fail.  Another option is to cause the whole function to
fail, but that seemed overkill.  I'm also not too happy about using a
goto here (not that I'm philosophically against them, but in this case
it seems awkward).

In our internal tree it seems to help H8/300SX quite a bit.

Index: expmed.c
===================================================================
--- expmed.c    (revision 141404)
+++ expmed.c    (working copy)
@@ -681,17 +681,26 @@ store_bit_field_1 (rtx str_rtx, unsigned
       if (MEM_P (xop0))
        xop0 = adjust_address (xop0, byte_mode, offset);
 
       /* If xop0 is a register, we need it in OP_MODE
         to make it acceptable to the format of insv.  */
       if (GET_CODE (xop0) == SUBREG)
-       /* We can't just change the mode, because this might clobber op0,
-          and we will need the original value of op0 if insv fails.  */
-       xop0 = gen_rtx_SUBREG (op_mode, SUBREG_REG (xop0), SUBREG_BYTE (xop0));
+       {
+         /* We can't just change the mode, because this might clobber op0,
+            and we will need the original value of op0 if insv fails.  */
+         //xop0 = gen_rtx_SUBREG (op_mode, SUBREG_REG (xop0), SUBREG_BYTE 
(xop0));
+         xop0 = simplify_gen_subreg (op_mode, xop0, GET_MODE (xop0), 0);
+         if (!xop0)
+           goto cannot_use_insv_1;
+       }
       if (REG_P (xop0) && GET_MODE (xop0) != op_mode)
-       xop0 = gen_rtx_SUBREG (op_mode, xop0, 0);
+       {
+         xop0 = simplify_gen_subreg (op_mode, xop0, GET_MODE (xop0), 0);
+         if (!xop0)
+           goto cannot_use_insv_1;
+       }
 
       /* On big-endian machines, we count bits from the most significant.
         If the bit field insn does not, we must invert.  */
 
       if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
        xbitpos = unit - bitsize - xbitpos;
@@ -749,12 +758,13 @@ store_bit_field_1 (rtx str_rtx, unsigned
        {
          emit_insn (pat);
          return true;
        }
       delete_insns_since (last);
     }
+ cannot_use_insv_1:
 
   /* If OP0 is a memory, try copying it to a register and seeing if a
      cheap register alternative is available.  */
   if (HAVE_insv && MEM_P (op0))
     {
       enum machine_mode bestmode;
@@ -1492,13 +1502,17 @@ extract_bit_field_1 (rtx str_rtx, unsign
       rtx xspec_target_subreg = 0;
       rtx pat;
 
       /* If op0 is a register, we need it in EXT_MODE to make it
         acceptable to the format of ext(z)v.  */
       if (REG_P (xop0) && GET_MODE (xop0) != ext_mode)
-       xop0 = gen_rtx_SUBREG (ext_mode, xop0, 0);
+       {
+         xop0 = simplify_gen_subreg (ext_mode, xop0, GET_MODE (xop0), 0);
+         if (!xop0)
+           goto cannot_use_extv_1;
+       }
       if (MEM_P (xop0))
        /* Get ref to first byte containing part of the field.  */
        xop0 = adjust_address (xop0, byte_mode, xoffset);
 
       /* On big-endian machines, we count bits from the most significant.
         If the bit field insn does not, we must invert.  */
@@ -1546,12 +1560,13 @@ extract_bit_field_1 (rtx str_rtx, unsign
          if (xtarget == xspec_target_subreg)
            return xspec_target;
          return convert_extracted_bit_field (xtarget, mode, tmode, unsignedp);
        }
       delete_insns_since (last);
     }
+ cannot_use_extv_1:
 
   /* If OP0 is a memory, try copying it to a register and seeing if a
      cheap register alternative is available.  */
   if (ext_mode != MAX_MACHINE_MODE && MEM_P (op0))
     {
       enum machine_mode bestmode;

Reply via email to