[15/n] PR85694: Try to split existing casts in widened patterns
authorRichard Sandiford <richard.sandiford@arm.com>
Tue, 3 Jul 2018 10:03:17 +0000 (10:03 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Tue, 3 Jul 2018 10:03:17 +0000 (10:03 +0000)
The main over-widening patch can introduce quite a few extra casts,
and in many cases those casts simply "tap into" an intermediate
point in an existing extension.  E.g. if we have:

    unsigned char a;
    int ax = (int) a;

and a later operation using ax is shortened to "unsigned short",
we would need:

    unsigned short ax' = (unsigned short) a;

The a->ax extension requires one set of unpacks to get to unsigned
short and another set of unpacks to get to int.  The first set are
then duplicated for ax'.  If both ax and ax' are needed, the a->ax'
extension would end up counting twice during cost calculations.

This patch rewrites the original:

    int ax = (int) a;

into a pattern:

    unsigned short ax' = (unsigned short) a;
    int ax = (int) ax';

so that each extension only counts once.

2018-07-03  Richard Sandiford  <richard.sandiford@arm.com>

gcc/
* tree-vect-patterns.c (vect_split_statement): New function.
(vect_convert_input): Use it to try to split an existing cast.

gcc/testsuite/
* gcc.dg/vect/vect-over-widen-5.c: Test that the extensions
get split into two for use by the over-widening pattern.
* gcc.dg/vect/vect-over-widen-6.c: Likewise.
* gcc.dg/vect/vect-over-widen-7.c: Likewise.
* gcc.dg/vect/vect-over-widen-8.c: Likewise.
* gcc.dg/vect/vect-over-widen-9.c: Likewise.
* gcc.dg/vect/vect-over-widen-10.c: Likewise.
* gcc.dg/vect/vect-over-widen-11.c: Likewise.
* gcc.dg/vect/vect-over-widen-12.c: Likewise.
* gcc.dg/vect/vect-over-widen-13.c: Likewise.
* gcc.dg/vect/vect-over-widen-14.c: Likewise.
* gcc.dg/vect/vect-over-widen-15.c: Likewise.
* gcc.dg/vect/vect-over-widen-16.c: Likewise.
* gcc.dg/vect/vect-over-widen-22.c: New test.

From-SVN: r262334

16 files changed:
gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/vect/vect-over-widen-10.c
gcc/testsuite/gcc.dg/vect/vect-over-widen-11.c
gcc/testsuite/gcc.dg/vect/vect-over-widen-12.c
gcc/testsuite/gcc.dg/vect/vect-over-widen-13.c
gcc/testsuite/gcc.dg/vect/vect-over-widen-14.c
gcc/testsuite/gcc.dg/vect/vect-over-widen-15.c
gcc/testsuite/gcc.dg/vect/vect-over-widen-16.c
gcc/testsuite/gcc.dg/vect/vect-over-widen-22.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/vect/vect-over-widen-5.c
gcc/testsuite/gcc.dg/vect/vect-over-widen-6.c
gcc/testsuite/gcc.dg/vect/vect-over-widen-7.c
gcc/testsuite/gcc.dg/vect/vect-over-widen-8.c
gcc/testsuite/gcc.dg/vect/vect-over-widen-9.c
gcc/tree-vect-patterns.c

index ab97a84fb0bbc65b82a7bc0f46b81663213ae7bc..fd928b0a1fd06c0f83dd15cbcf5f812b3960383b 100644 (file)
@@ -1,3 +1,8 @@
+2018-07-03  Richard Sandiford  <richard.sandiford@arm.com>
+
+       * tree-vect-patterns.c (vect_split_statement): New function.
+       (vect_convert_input): Use it to try to split an existing cast.
+
 2018-07-03  Richard Sandiford  <richard.sandiford@arm.com>
 
        * poly-int.h (print_hex): New function.
index 0028d4f88ace6cbfb2b3b99627e4e224659dab72..90aa4d7e22a327ce59bbab3d1ccf748af8266841 100644 (file)
@@ -1,3 +1,20 @@
+2018-07-03  Richard Sandiford  <richard.sandiford@arm.com>
+
+       * gcc.dg/vect/vect-over-widen-5.c: Test that the extensions
+       get split into two for use by the over-widening pattern.
+       * gcc.dg/vect/vect-over-widen-6.c: Likewise.
+       * gcc.dg/vect/vect-over-widen-7.c: Likewise.
+       * gcc.dg/vect/vect-over-widen-8.c: Likewise.
+       * gcc.dg/vect/vect-over-widen-9.c: Likewise.
+       * gcc.dg/vect/vect-over-widen-10.c: Likewise.
+       * gcc.dg/vect/vect-over-widen-11.c: Likewise.
+       * gcc.dg/vect/vect-over-widen-12.c: Likewise.
+       * gcc.dg/vect/vect-over-widen-13.c: Likewise.
+       * gcc.dg/vect/vect-over-widen-14.c: Likewise.
+       * gcc.dg/vect/vect-over-widen-15.c: Likewise.
+       * gcc.dg/vect/vect-over-widen-16.c: Likewise.
+       * gcc.dg/vect/vect-over-widen-22.c: New test.
+
 2018-07-03  Richard Sandiford  <richard.sandiford@arm.com>
 
        * gcc.dg/vect/vect-widen-mult-u8-u32.c: Check specifically for a
index 394a5a19e0d59fb7ca054ecd64ac909f645dd61d..f0140e4ef6d70cd61aa7dbb3ba39b1da142a79b2 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "vect-over-widen-9.c"
 
+/* { dg-final { scan-tree-dump {Splitting statement} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* \+ } "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* >> 1} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* >> 2} "vect" } } */
index 97ab57f12c439169cee9ea8153a33a1e89c97e70..222d854b2d6e3b606e83131862c2d23a56f11829 100644 (file)
@@ -55,6 +55,7 @@ main (void)
   return 0;
 }
 
+/* { dg-final { scan-tree-dump {Splitting statement} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* \+ } "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* >> 1} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* >> 2} "vect" } } */
index 0d5473ea1668b301f8ca56c37dfe422d82532862..ddb3bd8c0d378f0138c8cc7f9c6ea3300744b8a8 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "vect-over-widen-11.c"
 
+/* { dg-final { scan-tree-dump {Splitting statement} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* \+ } "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* >> 1} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* >> 2} "vect" } } */
index b89ed8bf4a7d2edeada5a7681bc9f8d988651132..b25db881afbc668bb163915a893bfb8b83243f32 100644 (file)
@@ -43,6 +43,7 @@ main (void)
   return 0;
 }
 
+/* { dg-final { scan-tree-dump {Splitting statement} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* \+} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* / 2} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_cast_forwprop_pattern: detected:[^\n]* = \(signed char\)} "vect" } } */
index 7b5ba2311a071add5b62f21398929a25488b149d..dfa09f5d2cafe329e6d57b5cc681786cc2c7d215 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "vect-over-widen-13.c"
 
+/* { dg-final { scan-tree-dump {Splitting statement} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* \+} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* >> 1} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_cast_forwprop_pattern: detected:[^\n]* = \(unsigned char\)} "vect" } } */
index e898e87fd0bc46f32b726669deb110640ab47eef..d31050ee926ac7e12c8bce99bf3edc26a1b11fbe 100644 (file)
@@ -45,6 +45,7 @@ main (void)
   return 0;
 }
 
+/* { dg-final { scan-tree-dump {Splitting statement} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* \+} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* / 2} "vect" } } */
 /* { dg-final { scan-tree-dump-not {vect_recog_cast_forwprop_pattern: detected} "vect" } } */
index 04293454d32b0049a9d2e0e87883fe965b6fd2d1..4584c586da1e6f13e8c8de4c1291cea0141ebab5 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "vect-over-widen-15.c"
 
+/* { dg-final { scan-tree-dump {Splitting statement} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* \+} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* >> 1} "vect" } } */
 /* { dg-final { scan-tree-dump-not {vect_recog_cast_forwprop_pattern: detected} "vect" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-over-widen-22.c b/gcc/testsuite/gcc.dg/vect/vect-over-widen-22.c
new file mode 100644 (file)
index 0000000..187bdf1
--- /dev/null
@@ -0,0 +1,53 @@
+/* { dg-require-effective-target vect_int } */
+/* { dg-require-effective-target vect_shift } */
+/* { dg-require-effective-target vect_pack_trunc } */
+/* { dg-require-effective-target vect_unpack } */
+
+#include "tree-vect.h"
+
+#define N 111
+
+/* The addition should be narrowed to short.  */
+
+void __attribute__ ((noipa))
+f (unsigned int *restrict a, unsigned int *restrict b,
+   unsigned short *restrict c, unsigned char *restrict d, unsigned int e)
+{
+  e &= 0xff;
+  for (__INTPTR_TYPE__ i = 0; i < N; ++i)
+    {
+      unsigned int xor = d[i] ^ e;
+      a[i] = c[i] | xor;
+      b[i] = xor;
+    }
+}
+
+int
+main (void)
+{
+  check_vect ();
+
+  unsigned int a[N], b[N];
+  unsigned short c[N];
+  unsigned char d[N];
+  for (int i = 0; i < N; ++i)
+    {
+      c[i] = i * 11;
+      d[i] = i * 2 + 3;
+      asm volatile ("" ::: "memory");
+    }
+  f (a, b, c, d, 0x73);
+  for (int i = 0; i < N; ++i)
+    if (b[i] != ((i * 2 + 3) ^ 0x73)
+       || a[i] != ((i * 11) | b[i]))
+      __builtin_abort ();
+
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump {Splitting pattern statement} "vect" } } */
+/* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* \^} "vect" } } */
+/* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* \|} "vect" } } */
+/* { dg-final { scan-tree-dump {demoting [^\n]* to [^\n]*char} "vect" } } */
+/* { dg-final { scan-tree-dump {demoting [^\n]* to [^\n]*short} "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" } } */
index 56d2396e394079861a906ff2ea1db81f2f01a7af..269df5387d20c859806da03aed91d77955fa651a 100644 (file)
@@ -44,6 +44,7 @@ main (void)
   return 0;
 }
 
+/* { dg-final { scan-tree-dump {Splitting statement} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* \+ } "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* >> 1} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_cast_forwprop_pattern: detected:[^\n]* \(signed char\)} "vect" } } */
index 9fe0e056cc4ea6b1c60cde56ada4ce98bb3b1b7e..bda92c965e080dd3f48ec42b6bea16e79d9416cd 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "vect-over-widen-5.c"
 
+/* { dg-final { scan-tree-dump {Splitting statement} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* \+ } "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* >> 1} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_cast_forwprop_pattern: detected:[^\n]* \(unsigned char\)} "vect" } } */
index a8166b385056fedb3a2f22283669fcbdc30eb9b2..314a6828c53c161d2e63b88bdecf0cee9070a794 100644 (file)
@@ -46,6 +46,7 @@ main (void)
   return 0;
 }
 
+/* { dg-final { scan-tree-dump {Splitting statement} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* \+ } "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* >> 2} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_cast_forwprop_pattern: detected:[^\n]* \(signed char\)} "vect" } } */
index 238f577adea9658667864d45a7d2fcd339fdecf8..553c0712a79a1d19195dbdab7cbd6fa330685bea 100644 (file)
@@ -12,6 +12,7 @@
 
 #include "vect-over-widen-7.c"
 
+/* { dg-final { scan-tree-dump {Splitting statement} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* \+ } "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* >> 2} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_cast_forwprop_pattern: detected:[^\n]* \(unsigned char\)} "vect" } } */
index a50f8198bfd53677b0b019153efc3cb358786484..5baba09a575f0f316aac1a967e145dbbbdade5b4 100644 (file)
@@ -50,6 +50,7 @@ main (void)
   return 0;
 }
 
+/* { dg-final { scan-tree-dump {Splitting statement} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* \+ } "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* >> 1} "vect" } } */
 /* { dg-final { scan-tree-dump {vect_recog_over_widening_pattern: detected:[^\n]* >> 2} "vect" } } */
index 91076f41964b03a0929f719a2a6bd0989221af5e..a1649d8b0fec5b5486522de83dfd546b2e6ce7c6 100644 (file)
@@ -634,6 +634,97 @@ vect_recog_temp_ssa_var (tree type, gimple *stmt)
   return make_temp_ssa_name (type, stmt, "patt");
 }
 
+/* STMT2_INFO describes a type conversion that could be split into STMT1
+   followed by a version of STMT2_INFO that takes NEW_RHS as its first
+   input.  Try to do this using pattern statements, returning true on
+   success.  */
+
+static bool
+vect_split_statement (stmt_vec_info stmt2_info, tree new_rhs,
+                     gimple *stmt1, tree vectype)
+{
+  if (is_pattern_stmt_p (stmt2_info))
+    {
+      /* STMT2_INFO is part of a pattern.  Get the statement to which
+        the pattern is attached.  */
+      stmt_vec_info orig_stmt2_info
+       = vinfo_for_stmt (STMT_VINFO_RELATED_STMT (stmt2_info));
+      vect_init_pattern_stmt (stmt1, orig_stmt2_info, vectype);
+
+      if (dump_enabled_p ())
+       {
+         dump_printf_loc (MSG_NOTE, vect_location,
+                          "Splitting pattern statement: ");
+         dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt2_info->stmt, 0);
+       }
+
+      /* Since STMT2_INFO is a pattern statement, we can change it
+        in-situ without worrying about changing the code for the
+        containing block.  */
+      gimple_assign_set_rhs1 (stmt2_info->stmt, new_rhs);
+
+      if (dump_enabled_p ())
+       {
+         dump_printf_loc (MSG_NOTE, vect_location, "into: ");
+         dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt1, 0);
+         dump_printf_loc (MSG_NOTE, vect_location, "and: ");
+         dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt2_info->stmt, 0);
+       }
+
+      gimple_seq *def_seq = &STMT_VINFO_PATTERN_DEF_SEQ (orig_stmt2_info);
+      if (STMT_VINFO_RELATED_STMT (orig_stmt2_info) == stmt2_info->stmt)
+       /* STMT2_INFO is the actual pattern statement.  Add STMT1
+          to the end of the definition sequence.  */
+       gimple_seq_add_stmt_without_update (def_seq, stmt1);
+      else
+       {
+         /* STMT2_INFO belongs to the definition sequence.  Insert STMT1
+            before it.  */
+         gimple_stmt_iterator gsi = gsi_for_stmt (stmt2_info->stmt, def_seq);
+         gsi_insert_before_without_update (&gsi, stmt1, GSI_SAME_STMT);
+       }
+      return true;
+    }
+  else
+    {
+      /* STMT2_INFO doesn't yet have a pattern.  Try to create a
+        two-statement pattern now.  */
+      gcc_assert (!STMT_VINFO_RELATED_STMT (stmt2_info));
+      tree lhs_type = TREE_TYPE (gimple_get_lhs (stmt2_info->stmt));
+      tree lhs_vectype = get_vectype_for_scalar_type (lhs_type);
+      if (!lhs_vectype)
+       return false;
+
+      if (dump_enabled_p ())
+       {
+         dump_printf_loc (MSG_NOTE, vect_location,
+                          "Splitting statement: ");
+         dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt2_info->stmt, 0);
+       }
+
+      /* Add STMT1 as a singleton pattern definition sequence.  */
+      gimple_seq *def_seq = &STMT_VINFO_PATTERN_DEF_SEQ (stmt2_info);
+      vect_init_pattern_stmt (stmt1, stmt2_info, vectype);
+      gimple_seq_add_stmt_without_update (def_seq, stmt1);
+
+      /* Build the second of the two pattern statements.  */
+      tree new_lhs = vect_recog_temp_ssa_var (lhs_type, NULL);
+      gassign *new_stmt2 = gimple_build_assign (new_lhs, NOP_EXPR, new_rhs);
+      vect_set_pattern_stmt (new_stmt2, stmt2_info, lhs_vectype);
+
+      if (dump_enabled_p ())
+       {
+         dump_printf_loc (MSG_NOTE, vect_location,
+                          "into pattern statements: ");
+         dump_gimple_stmt (MSG_NOTE, TDF_SLIM, stmt1, 0);
+         dump_printf_loc (MSG_NOTE, vect_location, "and: ");
+         dump_gimple_stmt (MSG_NOTE, TDF_SLIM, new_stmt2, 0);
+       }
+
+      return true;
+    }
+}
+
 /* Convert UNPROM to TYPE and return the result, adding new statements
    to STMT_INFO's pattern definition statements if no better way is
    available.  VECTYPE is the vector form of TYPE.  */
@@ -662,6 +753,18 @@ vect_convert_input (stmt_vec_info stmt_info, tree type,
   tree new_op = vect_recog_temp_ssa_var (type, NULL);
   gassign *new_stmt = gimple_build_assign (new_op, NOP_EXPR, unprom->op);
 
+  /* If the operation is the input to a vectorizable cast, try splitting
+     that cast into two, taking the required result as a mid-way point.  */
+  if (unprom->caster)
+    {
+      tree lhs = gimple_get_lhs (unprom->caster->stmt);
+      if (TYPE_PRECISION (TREE_TYPE (lhs)) > TYPE_PRECISION (type)
+         && TYPE_PRECISION (type) > TYPE_PRECISION (unprom->type)
+         && (TYPE_UNSIGNED (unprom->type) || !TYPE_UNSIGNED (type))
+         && vect_split_statement (unprom->caster, new_op, new_stmt, vectype))
+       return new_op;
+    }
+
   /* If OP is an external value, see if we can insert the new statement
      on an incoming edge.  */
   if (unprom->dt == vect_external_def)