Avoid adding impossible copies in ira-conflicts.c:process_reg_shuffles
authorRichard Sandiford <richard.sandiford@arm.com>
Sat, 21 Sep 2019 12:57:13 +0000 (12:57 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Sat, 21 Sep 2019 12:57:13 +0000 (12:57 +0000)
If an insn requires two operands to be tied, and the input operand dies
in the insn, IRA acts as though there were a copy from the input to the
output with the same execution frequency as the insn.  Allocating the
same register to the input and the output then saves the cost of a move.

If there is no such tie, but an input operand nevertheless dies
in the insn, IRA creates a similar move, but with an eighth of the
frequency.  This helps to ensure that chains of instructions reuse
registers in a natural way, rather than using arbitrarily different
registers for no reason.

This heuristic seems to work well in the vast majority of cases.
However, for SVE, the handling of untied operands ends up creating
copies between dying predicate registers and vector outputs, even though
vector and predicate registers are distinct classes and can never be
tied.  This is a particular problem because the dying predicate tends
to be the loop control predicate, which is used by most instructions
in a vector loop and so (rightly) has a very high allocation priority.
Any copies involving the loop predicate therefore tend to get processed
before copies involving only vector registers.  The end result is that
we tend to allocate the output of the last vector instruction in a loop
ahead of its natural place in the allocation order and don't benefit
from chains created between vector registers.

This patch tries to avoid the problem by not adding register shuffle
copies if there appears to be no chance that the two operands could be
allocated to the same register.

2019-09-21  Richard Sandiford  <richard.sandiford@arm.com>

gcc/
* ira-conflicts.c (can_use_same_reg_p): New function.
(process_reg_shuffles): Take an insn parameter.  Ignore cases
in which input operand op_num could seemingly never be allocated
to the same register as the destination.
(add_insn_allocno_copies): Update call to process_reg_shuffles.

gcc/testsuite/
* gcc.target/aarch64/sve/cond_convert_1.c: Remove XFAILs.
* gcc.target/aarch64/sve/cond_convert_4.c: Likewise.
* gcc.target/aarch64/sve/cond_unary_2.c: Likewise.

From-SVN: r276018

gcc/ChangeLog
gcc/ira-conflicts.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/aarch64/sve/cond_convert_1.c
gcc/testsuite/gcc.target/aarch64/sve/cond_convert_4.c
gcc/testsuite/gcc.target/aarch64/sve/cond_unary_2.c

index ca23b27629c94c0faf370638c9e379af88207f02..f22714ede983160dd6c4bdae8647c0f6e7fc04f8 100644 (file)
@@ -1,3 +1,11 @@
+2019-09-21  Richard Sandiford  <richard.sandiford@arm.com>
+
+       * ira-conflicts.c (can_use_same_reg_p): New function.
+       (process_reg_shuffles): Take an insn parameter.  Ignore cases
+       in which input operand op_num could seemingly never be allocated
+       to the same register as the destination.
+       (add_insn_allocno_copies): Update call to process_reg_shuffles.
+
 2019-09-21  Richard Sandiford  <richard.sandiford@arm.com>
 
        * simplify-rtx.c (neg_const_int): Replace with...
index afbc2ec0d52066af6bc9991d9f48a83e74b3d1ef..c199309e7a61c174fd477b3449440fc81852b88c 100644 (file)
@@ -325,12 +325,37 @@ process_regs_for_copy (rtx reg1, rtx reg2, bool constraint_p,
   return true;
 }
 
-/* Process all of the output registers of the current insn which are
-   not bound (BOUND_P) and the input register REG (its operand number
+/* Return true if output operand OUTPUT and input operand INPUT of
+   INSN can use the same register class for at least one alternative.
+   INSN is already described in recog_data and recog_op_alt.  */
+static bool
+can_use_same_reg_p (rtx_insn *insn, int output, int input)
+{
+  alternative_mask preferred = get_preferred_alternatives (insn);
+  for (int nalt = 0; nalt < recog_data.n_alternatives; nalt++)
+    {
+      if (!TEST_BIT (preferred, nalt))
+       continue;
+
+      const operand_alternative *op_alt
+       = &recog_op_alt[nalt * recog_data.n_operands];
+      if (op_alt[input].matches == output)
+       return true;
+
+      if (ira_reg_class_intersect[op_alt[input].cl][op_alt[output].cl]
+         != NO_REGS)
+       return true;
+    }
+  return false;
+}
+
+/* Process all of the output registers of the current insn (INSN) which
+   are not bound (BOUND_P) and the input register REG (its operand number
    OP_NUM) which dies in the insn as if there were a move insn between
    them with frequency FREQ.  */
 static void
-process_reg_shuffles (rtx reg, int op_num, int freq, bool *bound_p)
+process_reg_shuffles (rtx_insn *insn, rtx reg, int op_num, int freq,
+                     bool *bound_p)
 {
   int i;
   rtx another_reg;
@@ -342,7 +367,13 @@ process_reg_shuffles (rtx reg, int op_num, int freq, bool *bound_p)
 
       if (!REG_SUBREG_P (another_reg) || op_num == i
          || recog_data.operand_type[i] != OP_OUT
-         || bound_p[i])
+         || bound_p[i]
+         || (!can_use_same_reg_p (insn, i, op_num)
+             && (recog_data.constraints[op_num][0] != '%'
+                 || !can_use_same_reg_p (insn, i, op_num + 1))
+             && (op_num == 0
+                 || recog_data.constraints[op_num - 1][0] != '%'
+                 || !can_use_same_reg_p (insn, i, op_num - 1))))
        continue;
 
       process_regs_for_copy (reg, another_reg, false, NULL, freq);
@@ -412,7 +443,8 @@ add_insn_allocno_copies (rtx_insn *insn)
           the corresponding allocno copies.  The cost will not
           correspond to a real move insn cost, so make the frequency
           smaller.  */
-       process_reg_shuffles (operand, i, freq < 8 ? 1 : freq / 8, bound_p);
+       process_reg_shuffles (insn, operand, i, freq < 8 ? 1 : freq / 8,
+                             bound_p);
     }
 }
 
index 05c25ee28ce2806db933888f69093f55df2127a2..d0c01e3138b3797beb2bc374f72684d9409ba7f9 100644 (file)
@@ -1,3 +1,9 @@
+2019-09-21  Richard Sandiford  <richard.sandiford@arm.com>
+
+       * gcc.target/aarch64/sve/cond_convert_1.c: Remove XFAILs.
+       * gcc.target/aarch64/sve/cond_convert_4.c: Likewise.
+       * gcc.target/aarch64/sve/cond_unary_2.c: Likewise.
+
 2019-09-20  Iain Sandoe  <iain@sandoe.co.uk>
 
        * gcc.target/i386/naked-1.c: Alter options to use non-
index 69468eb69be09d105228d8a2ea2dd6da0592893c..dcc30768f88ef33e456c69634add41174d4dc24b 100644 (file)
@@ -32,6 +32,5 @@ TEST_ALL (DEF_LOOP)
 /* { dg-final { scan-assembler-times {\tucvtf\tz[0-9]+\.d, p[0-7]/m,} 1 } } */
 
 /* { dg-final { scan-assembler-not {\tmov\tz} } } */
-/* At the moment we don't manage to avoid using MOVPRFX.  */
-/* { dg-final { scan-assembler-not {\tmovprfx\t} { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-not {\tmovprfx\t} } } */
 /* { dg-final { scan-assembler-not {\tsel\t} } } */
index 55b535fa0cf339722e5dbba3c444dcf0e3511a9f..7e5f2a73ed96a43bf5ca1c5a725f6f979fafac9d 100644 (file)
@@ -32,6 +32,5 @@ TEST_ALL (DEF_LOOP)
 /* { dg-final { scan-assembler-times {\tfcvtzu\tz[0-9]+\.d, p[0-7]/m,} 1 } } */
 
 /* { dg-final { scan-assembler-not {\tmov\tz} } } */
-/* At the moment we don't manage to avoid using MOVPRFX.  */
-/* { dg-final { scan-assembler-not {\tmovprfx\t} { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-not {\tmovprfx\t} } } */
 /* { dg-final { scan-assembler-not {\tsel\t} } } */
index adf828398bba67c810d015fcf7126511b5140f83..991ccf016d1e2233f3d12988d095404d8e9cabbf 100644 (file)
@@ -54,8 +54,5 @@ TEST_ALL (DEF_LOOP)
 /* { dg-final { scan-assembler-times {\tfneg\tz[0-9]+\.d, p[0-7]/m,} 1 } } */
 
 /* { dg-final { scan-assembler-not {\tmov\tz} } } */
-/* At the moment we don't manage to avoid using MOVPRFX for the
-   floating-point functions.  */
-/* { dg-final { scan-assembler-not {\tmovprfx\t} { xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {\tmovprfx\t} 6 } } */
+/* { dg-final { scan-assembler-not {\tmovprfx\t} } } */
 /* { dg-final { scan-assembler-not {\tsel\t} } } */