Accept code attributes as rtx codes in .md files
authorRichard Sandiford <richard.sandiford@arm.com>
Sun, 12 May 2019 11:28:01 +0000 (11:28 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Sun, 12 May 2019 11:28:01 +0000 (11:28 +0000)
The recent AArch64 absolute difference patterns had to go through
some hoops to pair max/min rtx codes with the same signedness.
I also need to pair signed/unsigned codes with sign/zero extension
for some SVE ACLE patterns.

This patch therefore supports <...> as rtx codes, like we already
do for modes.

2019-05-12  Richard Sandiford  <richard.sandiford@arm.com>

gcc/
* doc/md.texi: Document use of code attributes in rtx patterns.
* read-md.h (rtx_reader::rtx_alloc_for_name): New member function.
* read-rtl.c (find_code): Split out search loops into...
(maybe_find_code): ...this new function.
(check_code_iterator): Make the error message more informative.
(check_code_attribute): New function.
(rtx_reader::rtx_alloc_for_name): Likewise.
(rtx_reader::read_rtx_code): Use rtx_alloc_for_name.
* config/aarch64/predicates.md (aarch64_smin, aarch64_umin): Delete.
* config/aarch64/aarch64-simd.md (*aarch64_<su>abd<mode>_3): Use
<max_opp> directly as an rtx code instead of via a match_operator.
* config/aarch64/aarch64-sve.md (aarch64_<su>abd<mode>_3): Likewise.
(<su>abd<mode>_3): Update accordingly.

From-SVN: r271107

gcc/ChangeLog
gcc/config/aarch64/aarch64-simd.md
gcc/config/aarch64/aarch64-sve.md
gcc/config/aarch64/predicates.md
gcc/doc/md.texi
gcc/read-md.h
gcc/read-rtl.c

index 2628c240010c495f6199c1804cc547d33c170c4b..1a9c8c1e181915debc1c232093dff2dc964c7ffc 100644 (file)
@@ -1,3 +1,19 @@
+2019-05-12  Richard Sandiford  <richard.sandiford@arm.com>
+
+       * doc/md.texi: Document use of code attributes in rtx patterns.
+       * read-md.h (rtx_reader::rtx_alloc_for_name): New member function.
+       * read-rtl.c (find_code): Split out search loops into...
+       (maybe_find_code): ...this new function.
+       (check_code_iterator): Make the error message more informative.
+       (check_code_attribute): New function.
+       (rtx_reader::rtx_alloc_for_name): Likewise.
+       (rtx_reader::read_rtx_code): Use rtx_alloc_for_name.
+       * config/aarch64/predicates.md (aarch64_smin, aarch64_umin): Delete.
+       * config/aarch64/aarch64-simd.md (*aarch64_<su>abd<mode>_3): Use
+       <max_opp> directly as an rtx code instead of via a match_operator.
+       * config/aarch64/aarch64-sve.md (aarch64_<su>abd<mode>_3): Likewise.
+       (<su>abd<mode>_3): Update accordingly.
+
 2019-05-12  Iain Sandoe  <iain@sandoe.co.uk>
 
        * config/rs6000/rs6000.c (debug_stack_info): When -mdebug=stack
index e3852c5d182b70978d7603225fce55c0b8ee2894..2b7a0029146df4559ea1bfc3c0090954d6923682 100644 (file)
          (USMAX:VDQ_BHSI
            (match_operand:VDQ_BHSI 1 "register_operand" "w")
            (match_operand:VDQ_BHSI 2 "register_operand" "w"))
-         (match_operator 3 "aarch64_<max_opp>"
-           [(match_dup 1)
-            (match_dup 2)])))]
+         (<max_opp>:VDQ_BHSI
+           (match_dup 1)
+           (match_dup 2))))]
   "TARGET_SIMD"
   "<su>abd\t%0.<Vtype>, %1.<Vtype>, %2.<Vtype>"
   [(set_attr "type" "neon_abd<q>")]
index e94801d9f8690f90181b8a63c8fac4857fbe16d5..b9cb1fae98c1e67c04a6279e615e0130fa4f68f8 100644 (file)
   [(set_attr "movprfx" "*,yes")]
 )
 
-;; Helper expander for aarch64_<su>abd<mode>_3 to save the callers
-;; the hassle of constructing the other arm of the MINUS.
+;; Unpredicated integer absolute difference.
 (define_expand "<su>abd<mode>_3"
   [(use (match_operand:SVE_I 0 "register_operand"))
    (USMAX:SVE_I (match_operand:SVE_I 1 "register_operand")
   "TARGET_SVE"
   {
     rtx pred = force_reg (<VPRED>mode, CONSTM1_RTX (<VPRED>mode));
-    rtx other_arm = gen_rtx_<MAX_OPP> (<MODE>mode, operands[1], operands[2]);
     emit_insn (gen_aarch64_<su>abd<mode>_3 (operands[0], pred, operands[1],
-                                           operands[2], other_arm));
+                                           operands[2]));
     DONE;
   }
 )
             (USMAX:SVE_I
               (match_operand:SVE_I 2 "register_operand" "0, w")
               (match_operand:SVE_I 3 "register_operand" "w, w"))
-            (match_operator 4 "aarch64_<max_opp>"
-              [(match_dup 2)
-               (match_dup 3)]))]
+            (<max_opp>:SVE_I
+              (match_dup 2)
+              (match_dup 3)))]
          UNSPEC_MERGE_PTRUE))]
   "TARGET_SVE"
   "@
index 8e1b784217b0367dc647a87024e14e36de781008..10100ca830a0cd753ef5759e3ce09914b1046d26 100644 (file)
   (ior (match_operand 0 "register_operand")
        (match_operand 0 "const_scalar_int_operand")))
 
-(define_predicate "aarch64_smin"
-  (match_code "smin"))
-
-(define_predicate "aarch64_umin"
-  (match_code "umin"))
-
 ;; True for integer comparisons and for FP comparisons other than LTGT or UNEQ.
 (define_special_predicate "aarch64_comparison_operator"
   (match_code "eq,ne,le,lt,ge,gt,geu,gtu,leu,ltu,unordered,
index 30612a6aecb3c20c739d84e4e5e7c2f3a9cefb5f..b35bcaace00f72d0c0dcd99ae2d1a739f4408067 100644 (file)
@@ -10979,6 +10979,27 @@ Other attributes are defined using:
 (define_code_attr @var{name} [(@var{code1} "@var{value1}") @dots{} (@var{coden} "@var{valuen}")])
 @end smallexample
 
+Instruction patterns can use code attributes as rtx codes, which can be
+useful if two sets of codes act in tandem.  For example, the following
+@code{define_insn} defines two patterns, one calculating a signed absolute
+difference and another calculating an unsigned absolute difference:
+
+@smallexample
+(define_code_iterator any_max [smax umax])
+(define_code_attr paired_min [(smax "smin") (umax "umin")])
+(define_insn @dots{}
+  [(set (match_operand:SI 0 @dots{})
+        (minus:SI (any_max:SI (match_operand:SI 1 @dots{})
+                              (match_operand:SI 2 @dots{}))
+                  (<paired_min>:SI (match_dup 1) (match_dup 2))))]
+  @dots{})
+@end smallexample
+
+The signed version of the instruction uses @code{smax} and @code{smin}
+while the unsigned version uses @code{umax} and @code{umin}.  There
+are no versions that pair @code{smax} with @code{umin} or @code{umax}
+with @code{smin}.
+
 Here's an example of code iterators in action, taken from the MIPS port:
 
 @smallexample
index 18426f71d77f8b599e8d8f387fb3c1b27cc2f275..327f378eac0345ffcac48d5ce157abd94e8b255f 100644 (file)
@@ -337,6 +337,7 @@ class rtx_reader : public md_reader
   ~rtx_reader ();
 
   bool read_rtx (const char *rtx_name, vec<rtx> *rtxen);
+  rtx rtx_alloc_for_name (const char *);
   rtx read_rtx_code (const char *code_name);
   virtual rtx read_rtx_operand (rtx return_rtx, int idx);
   rtx read_nested_rtx ();
index ebd69bde531d7a9fc36d858d44940f7b6a68c1a1..f72b2c35c7db01a90a908872154a5b109c117e64 100644 (file)
@@ -194,22 +194,31 @@ static const compact_insn_name compact_insn_names[] = {
   { NOTE, "cnote" }
 };
 
-/* Implementations of the iterator_group callbacks for codes.  */
+/* Return the rtx code for NAME, or UNKNOWN if NAME isn't a valid rtx code.  */
 
-static int
-find_code (const char *name)
+static rtx_code
+maybe_find_code (const char *name)
 {
-  int i;
-
-  for (i = 0; i < NUM_RTX_CODE; i++)
+  for (int i = 0; i < NUM_RTX_CODE; i++)
     if (strcmp (GET_RTX_NAME (i), name) == 0)
-      return i;
+      return (rtx_code) i;
 
-  for (i = 0; i < (signed)ARRAY_SIZE (compact_insn_names); i++)
+  for (int i = 0; i < (signed)ARRAY_SIZE (compact_insn_names); i++)
     if (strcmp (compact_insn_names[i].name, name) == 0)
       return compact_insn_names[i].code;
 
-  fatal_with_file_and_line ("unknown rtx code `%s'", name);
+  return UNKNOWN;
+}
+
+/* Implementations of the iterator_group callbacks for codes.  */
+
+static int
+find_code (const char *name)
+{
+  rtx_code code = maybe_find_code (name);
+  if (code == UNKNOWN)
+    fatal_with_file_and_line ("unknown rtx code `%s'", name);
+  return code;
 }
 
 static void
@@ -1306,7 +1315,37 @@ check_code_iterator (struct mapping *iterator)
   for (v = iterator->values->next; v != 0; v = v->next)
     if (strcmp (GET_RTX_FORMAT (bellwether), GET_RTX_FORMAT (v->number)) != 0)
       fatal_with_file_and_line ("code iterator `%s' combines "
-                               "different rtx formats", iterator->name);
+                               "`%s' and `%s', which have different "
+                               "rtx formats", iterator->name,
+                               GET_RTX_NAME (bellwether),
+                               GET_RTX_NAME (v->number));
+}
+
+/* Check that all values of attribute ATTR are rtx codes that have a
+   consistent format.  Return a representative code.  */
+
+static rtx_code
+check_code_attribute (mapping *attr)
+{
+  rtx_code bellwether = UNKNOWN;
+  for (map_value *v = attr->values; v != 0; v = v->next)
+    {
+      rtx_code code = maybe_find_code (v->string);
+      if (code == UNKNOWN)
+       fatal_with_file_and_line ("code attribute `%s' contains "
+                                 "unrecognized rtx code `%s'",
+                                 attr->name, v->string);
+      if (bellwether == UNKNOWN)
+       bellwether = code;
+      else if (strcmp (GET_RTX_FORMAT (bellwether),
+                      GET_RTX_FORMAT (code)) != 0)
+       fatal_with_file_and_line ("code attribute `%s' combines "
+                                 "`%s' and `%s', which have different "
+                                 "rtx formats", attr->name,
+                                 GET_RTX_NAME (bellwether),
+                                 GET_RTX_NAME (code));
+    }
+  return bellwether;
 }
 
 /* Read an rtx-related declaration from the MD file, given that it
@@ -1467,6 +1506,54 @@ parse_reg_note_name (const char *string)
   fatal_with_file_and_line ("unrecognized REG_NOTE name: `%s'", string);
 }
 
+/* Allocate an rtx for code NAME.  If NAME is a code iterator or code
+   attribute, record its use for later and use one of its possible
+   values as an interim rtx code.  */
+
+rtx
+rtx_reader::rtx_alloc_for_name (const char *name)
+{
+#ifdef GENERATOR_FILE
+  size_t len = strlen (name);
+  if (name[0] == '<' && name[len - 1] == '>')
+    {
+      /* Copy the attribute string into permanent storage, without the
+        angle brackets around it.  */
+      obstack *strings = get_string_obstack ();
+      obstack_grow0 (strings, name + 1, len - 2);
+      char *deferred_name = XOBFINISH (strings, char *);
+
+      /* Find the name of the attribute.  */
+      const char *attr = strchr (deferred_name, ':');
+      if (!attr)
+       attr = deferred_name;
+
+      /* Find the attribute itself.  */
+      mapping *m = (mapping *) htab_find (codes.attrs, &attr);
+      if (!m)
+       fatal_with_file_and_line ("unknown code attribute `%s'", attr);
+
+      /* Pick the first possible code for now, and record the attribute
+        use for later.  */
+      rtx x = rtx_alloc (check_code_attribute (m));
+      record_attribute_use (&codes, x, 0, deferred_name);
+      return x;
+    }
+
+  mapping *iterator = (mapping *) htab_find (codes.iterators, &name);
+  if (iterator != 0)
+    {
+      /* Pick the first possible code for now, and record the iterator
+        use for later.  */
+      rtx x = rtx_alloc (rtx_code (iterator->values->number));
+      record_iterator_use (iterator, x, 0);
+      return x;
+    }
+#endif
+
+  return rtx_alloc (rtx_code (codes.find_builtin (name)));
+}
+
 /* Subroutine of read_rtx and read_nested_rtx.  CODE_NAME is the name of
    either an rtx code or a code iterator.  Parse the rest of the rtx and
    return it.  */
@@ -1475,7 +1562,6 @@ rtx
 rtx_reader::read_rtx_code (const char *code_name)
 {
   RTX_CODE code;
-  struct mapping *iterator = NULL;
   const char *format_ptr;
   struct md_name name;
   rtx return_rtx;
@@ -1509,20 +1595,9 @@ rtx_reader::read_rtx_code (const char *code_name)
       return return_rtx;
     }
 
-  /* If this code is an iterator, build the rtx using the iterator's
-     first value.  */
-#ifdef GENERATOR_FILE
-  iterator = (struct mapping *) htab_find (codes.iterators, &code_name);
-  if (iterator != 0)
-    code = (enum rtx_code) iterator->values->number;
-  else
-    code = (enum rtx_code) codes.find_builtin (code_name);
-#else
-    code = (enum rtx_code) codes.find_builtin (code_name);
-#endif
-
   /* If we end up with an insn expression then we free this space below.  */
-  return_rtx = rtx_alloc (code);
+  return_rtx = rtx_alloc_for_name (code_name);
+  code = GET_CODE (return_rtx);
   format_ptr = GET_RTX_FORMAT (code);
   memset (return_rtx, 0, RTX_CODE_SIZE (code));
   PUT_CODE (return_rtx, code);
@@ -1534,9 +1609,6 @@ rtx_reader::read_rtx_code (const char *code_name)
       m_reuse_rtx_by_id[reuse_id] = return_rtx;
     }
 
-  if (iterator)
-    record_iterator_use (iterator, return_rtx, 0);
-
   /* Check for flags. */
   read_flags (return_rtx);