On 26/10/2020 06:51, Segher Boessenkool wrote:
> On Mon, Oct 26, 2020 at 11:06:22AM +0000, Alex Coplan wrote:
> > Well, only the low 32 bits of the subreg are valid. But because those
> > low 32 bits are shifted left 2 times, the low 34 bits of the ashift are
> > valid: the bottom 2 bits of the ashift are zeros, and the 32 bits above
> > those are from the inner SImode reg (with the upper 62 bits being
> > undefined).
> 
> Ugh.  Yes, I think you are right.  One more reason why we should only
> use *explicit* sign/zero extends, none of this confusing subreg
> business :-(

Yeah. IIRC expand_compound_operation() introduces the subreg because it
explicitly wants to rewrite the sign_extend using a pair of shifts (without
using an extend rtx). Something like:

(ashiftrt:DI
  (ashift:DI
    (subreg:DI (reg:SI r) 0)
    (const_int 32))
  (const_int 32))

> 
> > > > diff --git a/gcc/combine.c b/gcc/combine.c
> > > > index c88382efbd3..fe8eff2b464 100644
> > > > --- a/gcc/combine.c
> > > > +++ b/gcc/combine.c
> > > > @@ -7419,8 +7419,8 @@ expand_compound_operation (rtx x)
> > > >      }
> > > >  
> > > >    /* If we reach here, we want to return a pair of shifts.  The inner
> > > > -     shift is a left shift of BITSIZE - POS - LEN bits.  The outer
> > > > -     shift is a right shift of BITSIZE - LEN bits.  It is arithmetic or
> > > > +     shift is a left shift of MODEWIDTH - POS - LEN bits.  The outer
> > > > +     shift is a right shift of MODEWIDTH - LEN bits.  It is arithmetic 
> > > > or
> > > >       logical depending on the value of UNSIGNEDP.
> > > >  
> > > >       If this was a ZERO_EXTEND or ZERO_EXTRACT, this pair of shifts 
> > > > will be
> > > 
> > > MODEWIDTH isn't defined here yet, it is initialised just below to
> > > MODE_PRECISION (mode).
> > 
> > Yes, but bitsize isn't defined at all in this function AFAICT. Are
> > comments not permitted to refer to variables defined immediately beneath
> > them?
> 
> Of course you can -- comments are free form text after all -- but as
> written it suggest there already is an initialised variable "modewidth".
> 
> Just move the initialisation to above this comment?

Sure, see the revised patch attached.

Thanks,
Alex
diff --git a/gcc/combine.c b/gcc/combine.c
index 4782e1d9dcc..d4793c1c575 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -7418,9 +7418,11 @@ expand_compound_operation (rtx x)
 
     }
 
+  modewidth = GET_MODE_PRECISION (mode);
+
   /* If we reach here, we want to return a pair of shifts.  The inner
-     shift is a left shift of BITSIZE - POS - LEN bits.  The outer
-     shift is a right shift of BITSIZE - LEN bits.  It is arithmetic or
+     shift is a left shift of MODEWIDTH - POS - LEN bits.  The outer
+     shift is a right shift of MODEWIDTH - LEN bits.  It is arithmetic or
      logical depending on the value of UNSIGNEDP.
 
      If this was a ZERO_EXTEND or ZERO_EXTRACT, this pair of shifts will be
@@ -7433,7 +7435,6 @@ expand_compound_operation (rtx x)
      extraction.  Then the constant of 31 would be substituted in
      to produce such a position.  */
 
-  modewidth = GET_MODE_PRECISION (mode);
   if (modewidth >= pos + len)
     {
       tem = gen_lowpart (mode, XEXP (x, 0));
@@ -7650,20 +7651,27 @@ make_extraction (machine_mode mode, rtx inner, 
HOST_WIDE_INT pos,
        is_mode = GET_MODE (SUBREG_REG (inner));
       inner = SUBREG_REG (inner);
     }
-  else if (GET_CODE (inner) == ASHIFT
+  else if ((GET_CODE (inner) == ASHIFT || GET_CODE (inner) == MULT)
           && CONST_INT_P (XEXP (inner, 1))
-          && pos_rtx == 0 && pos == 0
-          && len > UINTVAL (XEXP (inner, 1)))
-    {
-      /* We're extracting the least significant bits of an rtx
-        (ashift X (const_int C)), where LEN > C.  Extract the
-        least significant (LEN - C) bits of X, giving an rtx
-        whose mode is MODE, then shift it left C times.  */
-      new_rtx = make_extraction (mode, XEXP (inner, 0),
-                            0, 0, len - INTVAL (XEXP (inner, 1)),
-                            unsignedp, in_dest, in_compare);
-      if (new_rtx != 0)
-       return gen_rtx_ASHIFT (mode, new_rtx, XEXP (inner, 1));
+          && pos_rtx == 0 && pos == 0)
+    {
+      const HOST_WIDE_INT ci = INTVAL (XEXP (inner, 1));
+      const auto code = GET_CODE (inner);
+      const HOST_WIDE_INT shift_amt = (code == MULT) ? exact_log2 (ci) : ci;
+
+      if (shift_amt > 0 && len > (unsigned HOST_WIDE_INT)shift_amt)
+       {
+         /* We're extracting the least significant bits of an rtx
+            (ashift X (const_int C)) or (mult X (const_int (2^C))),
+            where LEN > C.  Extract the least significant (LEN - C) bits
+            of X, giving an rtx whose mode is MODE, then shift it left
+            C times.  */
+         new_rtx = make_extraction (mode, XEXP (inner, 0),
+                                0, 0, len - shift_amt,
+                                unsignedp, in_dest, in_compare);
+         if (new_rtx)
+           return gen_rtx_fmt_ee (code, mode, new_rtx, XEXP (inner, 1));
+       }
     }
   else if (GET_CODE (inner) == TRUNCATE
           /* If trying or potentionally trying to extract

Reply via email to