There are several situations that combine.c:change_zero_ext does not
handle well yet.  One of them is

  (and:SI (subreg:SI (zero_extract:DI (reg:DI) ...) ...)
(with const_int operands to "and" and "zero_extract")

=>

  (and:SI (subreg:SI (and:DI (lshiftrt:DI ...)))

with two nested "and"s.  Another one is

  (zero_extract:DI (foo:SI) ...)

which is ignored by change_zero_ext.  Attached are two
experimental patches:

0001-*

  Deal with mode expanding zero_extracts in change_zero_ext.  The
  patch looks good to me, but not sure whether endianness is
  handled properly.  Is the second argument of gen_rtx_SUBREG
  correct?

0002-*

  This is a work in progress with the goal of fixing the first
  problem and similar ones by calling simplify_set after
  change_zero_ext to get rid of the overly complex code.  That
  works fine in principle, but replaces back the (and (lshiftrt
  ...) ...) that change_zero_ext generates back into zero_extract
  form.  Fiddling with simplify_set and make_compound_operation* a
  bit, trying to suppress undoing the transformations that
  change_zero_ext has just done, resulted in the (unfinished)
  patch.

As it's not clear to me whether this is a valid approach I'd
appreciate any advice on the patch or alternative ways of doing
that.

Ciao

Dominik ^_^  ^_^

-- 

Dominik Vogt
IBM Germany
>From 600ed3dadd5bc2568ab53be8466686abaf27ff3f Mon Sep 17 00:00:00 2001
From: Dominik Vogt <v...@linux.vnet.ibm.com>
Date: Fri, 9 Dec 2016 02:48:30 +0100
Subject: [PATCH 1/2] combine: Handle mode expanding zero_extracts in
 change_zero_ext.

Example:

  (zero_extract:DI (reg:SI)
                   (const_int 24)
                   (const_int 0))

-->

  (and:DI (subreg:DI (lshiftrt:SI (reg:SI) (const_int 8))
                     0)
          (const_int 16777215))
---
 gcc/combine.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/gcc/combine.c b/gcc/combine.c
index b429453..e14a08f 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -11237,18 +11237,24 @@ change_zero_ext (rtx pat)
       if (GET_CODE (x) == ZERO_EXTRACT
          && CONST_INT_P (XEXP (x, 1))
          && CONST_INT_P (XEXP (x, 2))
-         && GET_MODE (XEXP (x, 0)) == mode)
+         && (GET_MODE (XEXP (x, 0)) == mode
+             || GET_MODE_PRECISION (GET_MODE (XEXP (x, 0)))
+                < GET_MODE_PRECISION (mode)))
        {
+         machine_mode inner_mode = GET_MODE (XEXP (x, 0));
+
          size = INTVAL (XEXP (x, 1));
 
          int start = INTVAL (XEXP (x, 2));
          if (BITS_BIG_ENDIAN)
-           start = GET_MODE_PRECISION (mode) - size - start;
+           start = GET_MODE_PRECISION (inner_mode) - size - start;
 
          if (start)
-           x = gen_rtx_LSHIFTRT (mode, XEXP (x, 0), GEN_INT (start));
+           x = gen_rtx_LSHIFTRT (inner_mode, XEXP (x, 0), GEN_INT (start));
          else
            x = XEXP (x, 0);
+         if (mode != inner_mode)
+           x = gen_rtx_SUBREG (mode, x, 0);
        }
       else if (GET_CODE (x) == ZERO_EXTEND
               && SCALAR_INT_MODE_P (mode)
-- 
2.3.0

>From 8566f5a551cfd98978577b24ff05e8341410a56f Mon Sep 17 00:00:00 2001
From: Dominik Vogt <v...@linux.vnet.ibm.com>
Date: Fri, 9 Dec 2016 15:56:15 +0100
Subject: [PATCH 2/2] combine: Call simplify_set after change_zero_ext.

---
 gcc/combine.c | 156 +++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 105 insertions(+), 51 deletions(-)

diff --git a/gcc/combine.c b/gcc/combine.c
index e14a08f..4c53fe1 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -431,12 +431,14 @@ static rtx *find_split_point (rtx *, rtx_insn *, bool);
 static rtx subst (rtx, rtx, rtx, int, int, int);
 static rtx combine_simplify_rtx (rtx, machine_mode, int, int);
 static rtx simplify_if_then_else (rtx);
-static rtx simplify_set (rtx);
+static rtx simplify_set (rtx, bool);
 static rtx simplify_logical (rtx);
 static rtx expand_compound_operation (rtx);
 static const_rtx expand_field_assignment (const_rtx);
 static rtx make_extraction (machine_mode, rtx, HOST_WIDE_INT,
                            rtx, unsigned HOST_WIDE_INT, int, int, int);
+static rtx make_compound_operation_1 (rtx, enum rtx_code, bool);
+static rtx make_compound_operation_no_zero_ext (rtx, enum rtx_code);
 static rtx extract_left_shift (rtx, int);
 static int get_pos_from_mask (unsigned HOST_WIDE_INT,
                              unsigned HOST_WIDE_INT *);
@@ -6186,7 +6188,7 @@ combine_simplify_rtx (rtx x, machine_mode op0_mode, int 
in_dest,
       return expand_compound_operation (x);
 
     case SET:
-      return simplify_set (x);
+      return simplify_set (x, true);
 
     case AND:
     case IOR:
@@ -6564,10 +6566,12 @@ simplify_if_then_else (rtx x)
   return x;
 }
 
-/* Simplify X, a SET expression.  Return the new expression.  */
+/* Simplify X, a SET expression.  Return the new expression.
+   Internally calls make_compound_operation_no_zero_ext instead of
+   make_compound_operation if ALLOW_ZERO_EXT is false.  */
 
 static rtx
-simplify_set (rtx x)
+simplify_set (rtx x, bool allow_zero_ext)
 {
   rtx src = SET_SRC (x);
   rtx dest = SET_DEST (x);
@@ -6757,7 +6761,10 @@ simplify_set (rtx x)
     {
       /* Get SET_SRC in a form where we have placed back any
         compound expressions.  Then do the checks below.  */
-      src = make_compound_operation (src, SET);
+      if (allow_zero_ext)
+       src = make_compound_operation (src, SET);
+      else
+       src = make_compound_operation_no_zero_ext (src, SET);
       SUBST (SET_SRC (x), src);
     }
 
@@ -7793,12 +7800,15 @@ extract_left_shift (rtx x, int count)
    - Return null.  This tells the caller to recurse on *X_PTR with IN_CODE
      equal to *NEXT_CODE_PTR, after which *X_PTR holds the final value.
 
-   - Return a new rtx, which the caller returns directly.  */
+   - Return a new rtx, which the caller returns directly.
+
+   If ALLOW_ZERO_EXT is false, skip transformations to
+   ZERO_EXTRACT and ZERO_EXTEND.  */
 
 static rtx
 make_compound_operation_int (machine_mode mode, rtx *x_ptr,
                             enum rtx_code in_code,
-                            enum rtx_code *next_code_ptr)
+                            enum rtx_code *next_code_ptr, bool allow_zero_ext)
 {
   rtx x = *x_ptr;
   enum rtx_code next_code = *next_code_ptr;
@@ -7809,6 +7819,7 @@ make_compound_operation_int (machine_mode mode, rtx 
*x_ptr,
   int i;
   rtx tem;
   bool equality_comparison = false;
+  int in_dest = allow_zero_ext ? 0 : 1;
 
   if (in_code == EQ)
     {
@@ -7831,7 +7842,8 @@ make_compound_operation_int (machine_mode mode, rtx 
*x_ptr,
          HOST_WIDE_INT count = INTVAL (XEXP (x, 1));
          HOST_WIDE_INT multval = HOST_WIDE_INT_1 << count;
 
-         new_rtx = make_compound_operation (XEXP (x, 0), next_code);
+         new_rtx = make_compound_operation_1 (XEXP (x, 0), next_code,
+                                              allow_zero_ext);
          if (GET_CODE (new_rtx) == NEG)
            {
              new_rtx = XEXP (new_rtx, 0);
@@ -7845,8 +7857,8 @@ make_compound_operation_int (machine_mode mode, rtx 
*x_ptr,
     case PLUS:
       lhs = XEXP (x, 0);
       rhs = XEXP (x, 1);
-      lhs = make_compound_operation (lhs, next_code);
-      rhs = make_compound_operation (rhs, next_code);
+      lhs = make_compound_operation_1 (lhs, next_code, allow_zero_ext);
+      rhs = make_compound_operation_1 (rhs, next_code, allow_zero_ext);
       if (GET_CODE (lhs) == MULT && GET_CODE (XEXP (lhs, 0)) == NEG)
        {
          tem = simplify_gen_binary (MULT, mode, XEXP (XEXP (lhs, 0), 0),
@@ -7873,8 +7885,8 @@ make_compound_operation_int (machine_mode mode, rtx 
*x_ptr,
     case MINUS:
       lhs = XEXP (x, 0);
       rhs = XEXP (x, 1);
-      lhs = make_compound_operation (lhs, next_code);
-      rhs = make_compound_operation (rhs, next_code);
+      lhs = make_compound_operation_1 (lhs, next_code, allow_zero_ext);
+      rhs = make_compound_operation_1 (rhs, next_code, allow_zero_ext);
       if (GET_CODE (rhs) == MULT && GET_CODE (XEXP (rhs, 0)) == NEG)
        {
          tem = simplify_gen_binary (MULT, mode, XEXP (XEXP (rhs, 0), 0),
@@ -7908,9 +7920,10 @@ make_compound_operation_int (machine_mode mode, rtx 
*x_ptr,
       if (GET_CODE (XEXP (x, 0)) == LSHIFTRT
          && (i = exact_log2 (UINTVAL (XEXP (x, 1)) + 1)) >= 0)
        {
-         new_rtx = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code);
+         new_rtx = make_compound_operation_1 (XEXP (XEXP (x, 0), 0), next_code,
+                                              allow_zero_ext);
          new_rtx = make_extraction (mode, new_rtx, 0, XEXP (XEXP (x, 0), 1), 
i, 1,
-                                0, in_code == COMPARE);
+                                in_dest, in_code == COMPARE);
        }
 
       /* Same as previous, but for (subreg (lshiftrt ...)) in first op.  */
@@ -7921,10 +7934,11 @@ make_compound_operation_int (machine_mode mode, rtx 
*x_ptr,
        {
          rtx inner_x0 = SUBREG_REG (XEXP (x, 0));
          machine_mode inner_mode = GET_MODE (inner_x0);
-         new_rtx = make_compound_operation (XEXP (inner_x0, 0), next_code);
+         new_rtx = make_compound_operation_1 (XEXP (inner_x0, 0), next_code,
+                                              allow_zero_ext);
          new_rtx = make_extraction (inner_mode, new_rtx, 0,
                                     XEXP (inner_x0, 1),
-                                    i, 1, 0, in_code == COMPARE);
+                                    i, 1, in_dest, in_code == COMPARE);
 
          if (new_rtx)
            {
@@ -7943,9 +7957,10 @@ make_compound_operation_int (machine_mode mode, rtx 
*x_ptr,
             its own.  */
          if (!new_rtx && i >= 0)
            {
-             new_rtx = make_compound_operation (XEXP (x, 0), next_code);
+             new_rtx = make_compound_operation_1 (XEXP (x, 0), next_code,
+                                                  allow_zero_ext);
              new_rtx = make_extraction (mode, new_rtx, 0, NULL_RTX, i, 1,
-                                        0, in_code == COMPARE);
+                                        in_dest, in_code == COMPARE);
            }
        }
       /* Same as previous, but for (xor/ior (lshiftrt...) (lshiftrt...)).  */
@@ -7961,7 +7976,8 @@ make_compound_operation_int (machine_mode mode, rtx 
*x_ptr,
                                             XEXP (x, 1)),
                                gen_rtx_AND (mode, XEXP (XEXP (x, 0), 1),
                                             XEXP (x, 1)));
-         new_rtx = make_compound_operation (new_rtx, in_code);
+         new_rtx = make_compound_operation_1 (new_rtx, in_code,
+                                              allow_zero_ext);
        }
 
       /* If we are have (and (rotate X C) M) and C is larger than the number
@@ -7972,11 +7988,12 @@ make_compound_operation_int (machine_mode mode, rtx 
*x_ptr,
               && (i = exact_log2 (UINTVAL (XEXP (x, 1)) + 1)) >= 0
               && i <= INTVAL (XEXP (XEXP (x, 0), 1)))
        {
-         new_rtx = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code);
+         new_rtx = make_compound_operation_1 (XEXP (XEXP (x, 0), 0), next_code,
+                                              allow_zero_ext);
          new_rtx = make_extraction (mode, new_rtx,
                                 (GET_MODE_PRECISION (mode)
                                  - INTVAL (XEXP (XEXP (x, 0), 1))),
-                                NULL_RTX, i, 1, 0, in_code == COMPARE);
+                                NULL_RTX, i, 1, in_dest, in_code == COMPARE);
        }
 
       /* On machines without logical shifts, if the operand of the AND is
@@ -7996,8 +8013,9 @@ make_compound_operation_int (machine_mode mode, rtx 
*x_ptr,
          if ((INTVAL (XEXP (x, 1)) & ~mask) == 0)
            SUBST (XEXP (x, 0),
                   gen_rtx_ASHIFTRT (mode,
-                                    make_compound_operation
-                                    (XEXP (XEXP (x, 0), 0), next_code),
+                                    make_compound_operation_1
+                                    (XEXP (XEXP (x, 0), 0), next_code,
+                                     allow_zero_ext),
                                     XEXP (XEXP (x, 0), 1)));
        }
 
@@ -8007,9 +8025,10 @@ make_compound_operation_int (machine_mode mode, rtx 
*x_ptr,
         we are in a COMPARE.  */
       else if ((i = exact_log2 (UINTVAL (XEXP (x, 1)) + 1)) >= 0)
        new_rtx = make_extraction (mode,
-                              make_compound_operation (XEXP (x, 0),
-                                                       next_code),
-                              0, NULL_RTX, i, 1, 0, in_code == COMPARE);
+                              make_compound_operation_1 (XEXP (x, 0),
+                                                         next_code,
+                                                         allow_zero_ext),
+                              0, NULL_RTX, i, 1, in_dest, in_code == COMPARE);
 
       /* If we are in a comparison and this is an AND with a power of two,
         convert this into the appropriate bit extract.  */
@@ -8017,9 +8036,10 @@ make_compound_operation_int (machine_mode mode, rtx 
*x_ptr,
               && (i = exact_log2 (UINTVAL (XEXP (x, 1)))) >= 0
               && (equality_comparison || i < GET_MODE_PRECISION (mode) - 1))
        new_rtx = make_extraction (mode,
-                                  make_compound_operation (XEXP (x, 0),
-                                                           next_code),
-                                  i, NULL_RTX, 1, 1, 0, 1);
+                                  make_compound_operation_1 (XEXP (x, 0),
+                                                             next_code,
+                                                             allow_zero_ext),
+                                  i, NULL_RTX, 1, 1, in_dest, 1);
 
       /* If the one operand is a paradoxical subreg of a register or memory and
         the constant (limited to the smaller mode) has only zero bits where
@@ -8041,10 +8061,11 @@ make_compound_operation_int (machine_mode mode, rtx 
*x_ptr,
              mask = UINTVAL (XEXP (x, 1)) | (~nonzero_bits (sub, sub_mode));
              if ((mask & mode_mask) == mode_mask)
                {
-                 new_rtx = make_compound_operation (sub, next_code);
+                 new_rtx = make_compound_operation_1 (sub, next_code,
+                                                      allow_zero_ext);
                  new_rtx = make_extraction (mode, new_rtx, 0, 0,
                                             GET_MODE_PRECISION (sub_mode),
-                                            1, 0, in_code == COMPARE);
+                                            1, in_dest, in_code == COMPARE);
                }
            }
        }
@@ -8060,9 +8081,9 @@ make_compound_operation_int (machine_mode mode, rtx 
*x_ptr,
          && (nonzero_bits (XEXP (x, 0), mode) & (1 << (mode_width - 1))) == 0)
        {
          new_rtx = gen_rtx_ASHIFTRT (mode,
-                                 make_compound_operation (XEXP (x, 0),
-                                                          next_code),
-                                 XEXP (x, 1));
+                                     make_compound_operation_1
+                                     (XEXP (x, 0), next_code, allow_zero_ext),
+                                     XEXP (x, 1));
          break;
        }
 
@@ -8081,11 +8102,13 @@ make_compound_operation_int (machine_mode mode, rtx 
*x_ptr,
          && INTVAL (XEXP (lhs, 1)) >= 0
          && INTVAL (rhs) < mode_width)
        {
-         new_rtx = make_compound_operation (XEXP (lhs, 0), next_code);
+         new_rtx = make_compound_operation_1 (XEXP (lhs, 0), next_code,
+                                              allow_zero_ext);
          new_rtx = make_extraction (mode, new_rtx,
                                 INTVAL (rhs) - INTVAL (XEXP (lhs, 1)),
                                 NULL_RTX, mode_width - INTVAL (rhs),
-                                code == LSHIFTRT, 0, in_code == COMPARE);
+                                code == LSHIFTRT, in_dest,
+                                in_code == COMPARE);
          break;
        }
 
@@ -8102,9 +8125,10 @@ make_compound_operation_int (machine_mode mode, rtx 
*x_ptr,
          && INTVAL (rhs) < HOST_BITS_PER_WIDE_INT
          && INTVAL (rhs) < mode_width
          && (new_rtx = extract_left_shift (lhs, INTVAL (rhs))) != 0)
-       new_rtx = make_extraction (mode, make_compound_operation (new_rtx, 
next_code),
+       new_rtx = make_extraction (mode, make_compound_operation_1
+                                  (new_rtx, next_code, allow_zero_ext),
                               0, NULL_RTX, mode_width - INTVAL (rhs),
-                              code == LSHIFTRT, 0, in_code == COMPARE);
+                              code == LSHIFTRT, in_dest, in_code == COMPARE);
 
       break;
 
@@ -8125,13 +8149,14 @@ make_compound_operation_int (machine_mode mode, rtx 
*x_ptr,
                < GET_MODE_PRECISION (GET_MODE (inner)))
            && subreg_lowpart_p (x))
          {
-           new_rtx = make_compound_operation (XEXP (inner, 0), next_code);
+           new_rtx = make_compound_operation_1 (XEXP (inner, 0), next_code,
+                                                allow_zero_ext);
            int width = GET_MODE_PRECISION (GET_MODE (inner))
                        - INTVAL (XEXP (inner, 1));
            if (width > mode_width)
              width = mode_width;
            new_rtx = make_extraction (mode, new_rtx, 0, XEXP (inner, 1),
-                                      width, 1, 0, in_code == COMPARE);
+                                      width, 1, in_dest, in_code == COMPARE);
            break;
          }
 
@@ -8150,7 +8175,7 @@ make_compound_operation_int (machine_mode mode, rtx 
*x_ptr,
                       >= GET_MODE_BITSIZE (mode))))
          subreg_code = SET;
 
-       tem = make_compound_operation (inner, subreg_code);
+       tem = make_compound_operation_1 (inner, subreg_code, allow_zero_ext);
 
        simplified
          = simplify_subreg (mode, tem, GET_MODE (inner), SUBREG_BYTE (x));
@@ -8167,7 +8192,8 @@ make_compound_operation_int (machine_mode mode, rtx 
*x_ptr,
            /* If we have something other than a SUBREG, we might have
               done an expansion, so rerun ourselves.  */
            if (GET_CODE (newer) != SUBREG)
-             newer = make_compound_operation (newer, in_code);
+             newer = make_compound_operation_1 (newer, in_code,
+                                                allow_zero_ext);
 
            /* force_to_mode can expand compounds.  If it just re-expanded the
               compound, use gen_lowpart to convert to the desired mode.  */
@@ -8204,6 +8230,9 @@ make_compound_operation_int (machine_mode mode, rtx 
*x_ptr,
    equivalent to ZERO_EXTRACT, SIGN_EXTRACT, ZERO_EXTEND, SIGN_EXTEND.
    Form these expressions.
 
+   ZERO_EXTRACT and ZERO_EXTEND are only handled if ALLOW_ZERO_EXT
+   is true.
+
    Return the new rtx, usually just X.
 
    Also, for machines like the VAX that don't have logical shift insns,
@@ -8218,8 +8247,8 @@ make_compound_operation_int (machine_mode mode, rtx 
*x_ptr,
    a comparison or a COMPARE against zero, it is COMPARE, or EQ if more
    precisely it is an equality comparison against zero.  */
 
-rtx
-make_compound_operation (rtx x, enum rtx_code in_code)
+static rtx
+make_compound_operation_1 (rtx x, enum rtx_code in_code, bool allow_zero_ext)
 {
   enum rtx_code code = GET_CODE (x);
   const char *fmt;
@@ -8239,7 +8268,8 @@ make_compound_operation (rtx x, enum rtx_code in_code)
   if (SCALAR_INT_MODE_P (GET_MODE (x)))
     {
       rtx new_rtx = make_compound_operation_int (GET_MODE (x), &x,
-                                                in_code, &next_code);
+                                                in_code, &next_code,
+                                                allow_zero_ext);
       if (new_rtx)
        return new_rtx;
       code = GET_CODE (x);
@@ -8248,9 +8278,9 @@ make_compound_operation (rtx x, enum rtx_code in_code)
   /* Now recursively process each operand of this operation.  We need to
      handle ZERO_EXTEND specially so that we don't lose track of the
      inner mode.  */
-  if (code == ZERO_EXTEND)
+  if (allow_zero_ext && code == ZERO_EXTEND)
     {
-      new_rtx = make_compound_operation (XEXP (x, 0), next_code);
+      new_rtx = make_compound_operation_1 (XEXP (x, 0), next_code, true);
       tem = simplify_const_unary_operation (ZERO_EXTEND, GET_MODE (x),
                                            new_rtx, GET_MODE (XEXP (x, 0)));
       if (tem)
@@ -8263,19 +8293,35 @@ make_compound_operation (rtx x, enum rtx_code in_code)
   for (i = 0; i < GET_RTX_LENGTH (code); i++)
     if (fmt[i] == 'e')
       {
-       new_rtx = make_compound_operation (XEXP (x, i), next_code);
+       new_rtx = make_compound_operation_1 (XEXP (x, i), next_code,
+                                            allow_zero_ext);
        SUBST (XEXP (x, i), new_rtx);
       }
     else if (fmt[i] == 'E')
       for (j = 0; j < XVECLEN (x, i); j++)
        {
-         new_rtx = make_compound_operation (XVECEXP (x, i, j), next_code);
+         new_rtx = make_compound_operation_1 (XVECEXP (x, i, j), next_code,
+                                              allow_zero_ext);
          SUBST (XVECEXP (x, i, j), new_rtx);
        }
 
   maybe_swap_commutative_operands (x);
   return x;
 }
+
+rtx
+make_compound_operation (rtx x, enum rtx_code in_code)
+{
+  return make_compound_operation_1 (x, in_code, true);
+}
+
+/* Like make_compound_operation but does not transform to
+   ZERO_EXTEND and ZERO_EXTRACT.  */
+static rtx
+make_compound_operation_no_zero_ext (rtx x, enum rtx_code in_code)
+{
+  return make_compound_operation_1 (x, in_code, false);
+}
 
 /* Given M see if it is a value that would select a field of bits
    within an item, but not the entire word.  Return -1 if not.
@@ -11352,7 +11398,11 @@ recog_for_combine (rtx *pnewpat, rtx_insn *insn, rtx 
*pnotes)
   bool changed = false;
 
   if (GET_CODE (pat) == SET)
-    changed = change_zero_ext (pat);
+    {
+      changed = change_zero_ext (pat);
+      if (changed)
+       pat = simplify_set (pat, false);
+    }
   else if (GET_CODE (pat) == PARALLEL)
     {
       int i;
@@ -11360,7 +11410,11 @@ recog_for_combine (rtx *pnewpat, rtx_insn *insn, rtx 
*pnotes)
        {
          rtx set = XVECEXP (pat, 0, i);
          if (GET_CODE (set) == SET)
-           changed |= change_zero_ext (set);
+           if (change_zero_ext (set))
+             {
+               changed = true;
+               set = simplify_set (set, false);
+             }
        }
     }
 
-- 
2.3.0

Reply via email to