combine.c (is_parallel_of_n_reg_sets): New function.
authorSegher Boessenkool <segher@kernel.crashing.org>
Mon, 1 Dec 2014 22:36:12 +0000 (23:36 +0100)
committerSegher Boessenkool <segher@gcc.gnu.org>
Mon, 1 Dec 2014 22:36:12 +0000 (23:36 +0100)
* combine.c (is_parallel_of_n_reg_sets): New function.
(can_split_parallel_of_n_reg_sets): New function.
(try_combine): If I2 is a PARALLEL of two SETs, split it into
two insns if possible.

From-SVN: r218248

gcc/ChangeLog
gcc/combine.c

index 88cfeef98b2e454518c5bd3d366dd6dd1811464a..fc5e2db1eec6bb360d3be0ee87d0327fdd895701 100644 (file)
@@ -1,3 +1,10 @@
+2014-12-01  Segher Boessenkool  <segher@kernel.crashing.org>
+
+       * combine.c (is_parallel_of_n_reg_sets): New function.
+       (can_split_parallel_of_n_reg_sets): New function.
+       (try_combine): If I2 is a PARALLEL of two SETs, split it into
+       two insns if possible.
+
 2014-12-01  Tobias Burnus  <burnus@net-b.de>
            Jack Howarth  <howarth@bromo.med.uc.edu>
 
index afcb91eedd03ec60f5e261b4567938ed06740c30..b9319023c34150c61476d3d99cb92049b6ee0676 100644 (file)
@@ -2461,6 +2461,59 @@ update_cfg_for_uncondjump (rtx_insn *insn)
     }
 }
 
+/* Return whether INSN is a PARALLEL of exactly N register SETs followed
+   by an arbitrary number of CLOBBERs.  */
+static bool
+is_parallel_of_n_reg_sets (rtx_insn *insn, int n)
+{
+  rtx pat = PATTERN (insn);
+
+  if (GET_CODE (pat) != PARALLEL)
+    return false;
+
+  int len = XVECLEN (pat, 0);
+  if (len < n)
+    return false;
+
+  int i;
+  for (i = 0; i < n; i++)
+    if (GET_CODE (XVECEXP (pat, 0, i)) != SET
+       || !REG_P (SET_DEST (XVECEXP (pat, 0, i))))
+      return false;
+  for ( ; i < len; i++)
+    if (GET_CODE (XVECEXP (pat, 0, i)) != CLOBBER)
+      return false;
+
+  return true;
+}
+
+/* Return whether INSN, a PARALLEL of N register SETs (and maybe some
+   CLOBBERs), can be split into individual SETs in that order, without
+   changing semantics.  */
+static bool
+can_split_parallel_of_n_reg_sets (rtx_insn *insn, int n)
+{
+  if (!insn_nothrow_p (insn))
+    return false;
+
+  rtx pat = PATTERN (insn);
+
+  int i, j;
+  for (i = 0; i < n; i++)
+    {
+      if (side_effects_p (SET_SRC (XVECEXP (pat, 0, i))))
+       return false;
+
+      rtx reg = SET_DEST (XVECEXP (pat, 0, i));
+
+      for (j = i + 1; j < n; j++)
+       if (reg_referenced_p (reg, XVECEXP (pat, 0, j)))
+         return false;
+    }
+
+  return true;
+}
+
 /* Try to combine the insns I0, I1 and I2 into I3.
    Here I0, I1 and I2 appear earlier than I3.
    I0 and I1 can be zero; then we combine just I2 into I3, or I1 and I2 into
@@ -2817,6 +2870,31 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
                      alloc_insn_link (i1, regno, LOG_LINKS (i2)));
        }
     }
+
+  /* If I2 is a PARALLEL of two SETs of REGs (and perhaps some CLOBBERs),
+     make those two SETs separate I1 and I2 insns, and make an I0 that is
+     the original I1.  */
+  if (i0 == 0
+      && is_parallel_of_n_reg_sets (i2, 2)
+      && can_split_parallel_of_n_reg_sets (i2, 2)
+      && !reg_used_between_p (SET_DEST (XVECEXP (PATTERN (i2), 0, 0)), i2, i3)
+      && !reg_used_between_p (SET_DEST (XVECEXP (PATTERN (i2), 0, 1)), i2, i3))
+    {
+      /* If there is no I1, there is no I0 either.  */
+      i0 = i1;
+
+      /* We make I1 with the same INSN_UID as I2.  This gives it
+        the same DF_INSN_LUID for value tracking.  Our fake I1 will
+        never appear in the insn stream so giving it the same INSN_UID
+        as I2 will not cause a problem.  */
+
+      i1 = gen_rtx_INSN (VOIDmode, NULL, i2, BLOCK_FOR_INSN (i2),
+                        XVECEXP (PATTERN (i2), 0, 0), INSN_LOCATION (i2),
+                        -1, NULL_RTX);
+      INSN_UID (i1) = INSN_UID (i2);
+
+      SUBST (PATTERN (i2), XVECEXP (PATTERN (i2), 0, 1));
+    }
 #endif
 
   /* Verify that I2 and I1 are valid for combining.  */