From: Tamar Christina <Tamar.Christina@arm.com>
To: Mikael Morin <morin-mikael@orange.fr>,
Richard Earnshaw <Richard.Earnshaw@arm.com>,
"gcc-patches@gcc.gnu.org" <gcc-patches@gcc.gnu.org>,
nd <nd@arm.com>, Richard Sandiford <Richard.Sandiford@arm.com>
Subject: RE: [PATCH v2] machine descriptor: New compact syntax for insn and insn_split in Machine Descriptions.
Date: Tue, 13 Jun 2023 15:26:35 +0000 [thread overview]
Message-ID: <VI1PR08MB532501BE8432A4B569870958FF55A@VI1PR08MB5325.eurprd08.prod.outlook.com> (raw)
In-Reply-To: <30f06911-e19a-a39b-9b56-803cc9ef0ec1@orange.fr>
[-- Attachment #1: Type: text/plain, Size: 24786 bytes --]
Hi All,
Updated patch with feedback addressed.
Bootstrapped Regtested on aarch64-none-linux-gnu and no issues.
Any feedback?
Thanks,
Tamar
gcc/ChangeLog:
* gensupport.cc (class conlist, add_constraints, add_attributes,
skip_spaces, expect_char, preprocess_compact_syntax,
parse_section_layout, parse_section, convert_syntax): New.
(process_rtx): Check for conversion.
* genoutput.cc (process_template): Check for unresolved iterators.
(class data): Add compact_syntax_p.
(gen_insn): Use it.
* gensupport.h (compact_syntax): New.
(hash-set.h): Include.
Co-Authored-By: Omar Tahir <Omar.Tahir2@arm.com>
--- inline copy of patch ---
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 6a435eb44610960513e9739ac9ac1e8a27182c10..3bd1bcbc8beda9bbaea71c65118ecfa2cdace335 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -27,6 +27,7 @@ See the next chapter for information on the C header file.
from such an insn.
* Output Statement:: For more generality, write C code to output
the assembler code.
+* Compact Syntax:: Compact syntax for writing machine descriptors.
* Predicates:: Controlling what kinds of operands can be used
for an insn.
* Constraints:: Fine-tuning operand selection.
@@ -713,6 +714,167 @@ you can use @samp{*} inside of a @samp{@@} multi-alternative template:
@end group
@end smallexample
+@node Compact Syntax
+@section Compact Syntax
+@cindex compact syntax
+
+When a @code{define_insn} or @code{define_insn_and_split} has multiple
+alternatives it may be beneficial to use the compact syntax when specifying
+alternatives.
+
+This syntax puts the constraints and attributes on the same horizontal line as
+the instruction assembly template.
+
+As an example
+
+@smallexample
+@group
+(define_insn_and_split ""
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,k,r,r,r,r")
+ (match_operand:SI 1 "aarch64_mov_operand" " r,r,k,M,n,Usv"))]
+ ""
+ "@@
+ mov\\t%w0, %w1
+ mov\\t%w0, %w1
+ mov\\t%w0, %w1
+ mov\\t%w0, %1
+ #
+ * return aarch64_output_sve_cnt_immediate ('cnt', '%x0', operands[1]);"
+ "&& true"
+ [(const_int 0)]
+ @{
+ aarch64_expand_mov_immediate (operands[0], operands[1]);
+ DONE;
+ @}
+ [(set_attr "type" "mov_reg,mov_reg,mov_reg,mov_imm,mov_imm,mov_imm")
+ (set_attr "arch" "*,*,*,*,*,sve")
+ (set_attr "length" "4,4,4,4,*, 4")
+]
+)
+@end group
+@end smallexample
+
+can be better expressed as:
+
+@smallexample
+@group
+(define_insn_and_split ""
+ [(set (match_operand:SI 0 "nonimmediate_operand")
+ (match_operand:SI 1 "aarch64_mov_operand"))]
+ ""
+ @{@@ [cons: =0, 1; attrs: type, arch, length]
+ [r , r ; mov_reg , * , 4] mov\t%w0, %w1
+ [k , r ; mov_reg , * , 4] ^
+ [r , k ; mov_reg , * , 4] ^
+ [r , M ; mov_imm , * , 4] mov\t%w0, %1
+ [r , n ; mov_imm , * , *] #
+ [r , Usv; mov_imm , sve , 4] << aarch64_output_sve_cnt_immediate ("cnt", "%x0", operands[1]);
+ @}
+ "&& true"
+ [(const_int 0)]
+ @{
+ aarch64_expand_mov_immediate (operands[0], operands[1]);
+ DONE;
+ @}
+)
+@end group
+@end smallexample
+
+The syntax rules are as follows:
+@itemize @bullet
+@item
+Templates must start with @samp{@{@@} to use the new syntax.
+
+@item
+@samp{@{@@} is followed by a layout in parentheses which is @samp{cons:}
+followed by a comma-separated list of @code{match_operand}/@code{match_scratch}
+operand numbers, then a semicolon, followed by the same for attributes
+(@samp{attrs:}). Operand modifiers can be placed in this section group as well.
+Both sections are optional (so you can use only @samp{cons}, or only
+@samp{attrs}, or both), and @samp{cons} must come before @samp{attrs} if
+present.
+
+@item
+Each alternative begins with any amount of whitespace.
+
+@item
+Following the whitespace is a comma-separated list of "constraints" and/or
+"attributes" within brackets @code{[]}, with sections separated by a semicolon.
+
+@item
+Should you want to copy the previous asm line, the symbol @code{^} can be used.
+This allows less copy pasting between alternative and reduces the number of
+lines to update on changes.
+
+@item
+When using C functions for output, the idiom @samp{* return @var{function};}
+can be replaced with the shorthand @samp{<< @var{function};}.
+
+@item
+Following the closing @samp{]} is any amount of whitespace, and then the actual
+asm output.
+
+@item
+Spaces are allowed in the list (they will simply be removed).
+
+@item
+All constraint alternatives should be specified. For example, a list of
+of three blank alternatives should be written @samp{[,,]} rather than
+@samp{[]}.
+
+@item
+All attribute alternatives should be non-empty, with @samp{*}
+representing the default attribute value. For example, a list of three
+default attribute values should be written @samp{[*,*,*]} rather than
+@samp{[]}.
+
+
+@item
+Within an @samp{@{@@} block both multiline and singleline C comments are
+allowed, but when used outside of a C block they must be the only non-whitespace
+blocks on the line.
+
+@item
+Within an @samp{@{@@} block, any iterators that do not get expanded will result
+in an error. If for some reason it is required to have @code{<} or @code{>} in
+the output then these must be escaped using @backslashchar{}.
+
+@item
+It is possible to use the @samp{attrs} list to specify some attributes and to
+use the normal @code{set_attr} syntax to specify other attributes. There must
+not be any overlap between the two lists.
+
+In other words, the following is valid:
+@smallexample
+@group
+(define_insn_and_split ""
+ [(set (match_operand:SI 0 "nonimmediate_operand")
+ (match_operand:SI 1 "aarch64_mov_operand"))]
+ ""
+ @{@@ [cons: 0, 1; attrs: type, arch, length]@}
+ @dots{}
+ [(set_attr "foo" "mov_imm")]
+)
+@end group
+@end smallexample
+
+but this is not valid:
+@smallexample
+@group
+(define_insn_and_split ""
+ [(set (match_operand:SI 0 "nonimmediate_operand")
+ (match_operand:SI 1 "aarch64_mov_operand"))]
+ ""
+ @{@@ [cons: 0, 1; attrs: type, arch, length]@}
+ @dots{}
+ [(set_attr "arch" "bar")
+ (set_attr "foo" "mov_imm")]
+)
+@end group
+@end smallexample
+
+because you can't mix and match new and old syntax.
+
@node Predicates
@section Predicates
@cindex predicates
diff --git a/gcc/genoutput.cc b/gcc/genoutput.cc
index 163e8dfef4ca2c2c92ce1cf001ee6be40a54ca3e..3fbdde70df30d23a11b23d59eefe95b86f148c76 100644
--- a/gcc/genoutput.cc
+++ b/gcc/genoutput.cc
@@ -157,6 +157,7 @@ public:
int n_alternatives; /* Number of alternatives in each constraint */
int operand_number; /* Operand index in the big array. */
int output_format; /* INSN_OUTPUT_FORMAT_*. */
+ bool compact_syntax_p;
struct operand_data operand[MAX_MAX_OPERANDS];
};
@@ -700,12 +701,51 @@ process_template (class data *d, const char *template_code)
if (sp != ep)
message_at (d->loc, "trailing whitespace in output template");
- while (cp < sp)
+ /* Check for any unexpanded iterators. */
+ if (bp[0] != '*' && d->compact_syntax_p)
{
- putchar (*cp);
- cp++;
+ const char *p = cp;
+ const char *last_bracket = nullptr;
+ while (p < sp)
+ {
+ if (*p == '\\' && p + 1 < sp)
+ {
+ putchar (*p);
+ putchar (*(p+1));
+ p += 2;
+ continue;
+ }
+
+ if (*p == '>' && last_bracket && *last_bracket == '<')
+ {
+ int len = p - last_bracket;
+ fatal_at (d->loc, "unresolved iterator '%.*s' in '%s'",
+ len - 1, last_bracket + 1, cp);
+ }
+ else if (*p == '<' || *p == '>')
+ last_bracket = p;
+
+ putchar (*p);
+ p += 1;
+ }
+
+ if (last_bracket)
+ {
+ char *nl = strchr (const_cast<char*> (cp), '\n');
+ if (nl)
+ *nl = '\0';
+ fatal_at (d->loc, "unmatched angle brackets, likely an "
+ "error in iterator syntax in %s", cp);
+ }
+ }
+ else
+ {
+ while (cp < sp)
+ putchar (*(cp++));
}
+ cp = sp;
+
if (!found_star)
puts ("\",");
else if (*bp != '*')
@@ -881,6 +921,8 @@ gen_insn (md_rtx_info *info)
else
d->name = 0;
+ d->compact_syntax_p = compact_syntax.contains (insn);
+
/* Build up the list in the same order as the insns are seen
in the machine description. */
d->next = 0;
diff --git a/gcc/gensupport.h b/gcc/gensupport.h
index a1edfbd71908b6244b40f801c6c01074de56777e..7925e22ed418767576567cad583bddf83c0846b1 100644
--- a/gcc/gensupport.h
+++ b/gcc/gensupport.h
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_GENSUPPORT_H
#define GCC_GENSUPPORT_H
+#include "hash-set.h"
#include "read-md.h"
struct obstack;
@@ -218,6 +219,8 @@ struct pattern_stats
int num_operand_vars;
};
+extern hash_set<rtx> compact_syntax;
+
extern void get_pattern_stats (struct pattern_stats *ranges, rtvec vec);
extern void compute_test_codes (rtx, file_location, char *);
extern file_location get_file_location (rtx);
diff --git a/gcc/gensupport.cc b/gcc/gensupport.cc
index f9efc6eb7572a44b8bb154b0b22be3815bd0d244..7b704284153f3702bc023194d9ef394d8722c3bd 100644
--- a/gcc/gensupport.cc
+++ b/gcc/gensupport.cc
@@ -18,6 +18,8 @@
<http://www.gnu.org/licenses/>. */
#include "bconfig.h"
+#define INCLUDE_STRING
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tm.h"
@@ -33,6 +35,8 @@
static rtx operand_data[MAX_OPERANDS];
static rtx match_operand_entries_in_pattern[MAX_OPERANDS];
static char used_operands_numbers[MAX_OPERANDS];
+/* List of entries which are part of the new syntax. */
+hash_set<rtx> compact_syntax;
/* In case some macros used by files we include need it, define this here. */
@@ -545,6 +549,485 @@ gen_rewrite_sequence (rtvec vec)
return new_vec;
}
+/* The following is for handling the compact syntax for constraints and
+ attributes.
+
+ The normal syntax looks like this:
+
+ ...
+ (match_operand: 0 "s_register_operand" "r,I,k")
+ (match_operand: 2 "s_register_operand" "r,k,I")
+ ...
+ "@
+ <asm>
+ <asm>
+ <asm>"
+ ...
+ (set_attr "length" "4,8,8")
+
+ The compact syntax looks like this:
+
+ ...
+ (match_operand: 0 "s_register_operand")
+ (match_operand: 2 "s_register_operand")
+ ...
+ {@ [cons: 0, 2; attrs: length]
+ [r,r; 4] <asm>
+ [I,k; 8] <asm>
+ [k,I; 8] <asm>
+ }
+ ...
+ [<other attributes>]
+
+ This is the only place where this syntax needs to be handled. Relevant
+ patterns are transformed from compact to the normal syntax before they are
+ queued, so none of the gen* programs need to know about this syntax at all.
+
+ Conversion process (convert_syntax):
+
+ 0) Check that pattern actually uses new syntax (check for {@ ... }).
+
+ 1) Get the "layout", i.e. the "[cons: 0 2; attrs: length]" from the above
+ example. cons must come first; both are optional. Set up two vecs,
+ convec and attrvec, for holding the results of the transformation.
+
+ 2) For each alternative: parse the list of constraints and/or attributes,
+ and enqueue them in the relevant lists in convec and attrvec. By the end
+ of this process, convec[N].con and attrvec[N].con should contain regular
+ syntax constraint/attribute lists like "r,I,k". Copy the asm to a string
+ as we go.
+
+ 3) Search the rtx and write the constraint and attribute lists into the
+ correct places. Write the asm back into the template. */
+
+/* Helper class for shuffling constraints/attributes in convert_syntax and
+ add_constraints/add_attributes. This includes commas but not whitespace. */
+
+class conlist {
+private:
+ std::string con;
+
+public:
+ std::string name;
+ int idx = -1;
+
+ conlist () = default;
+
+ /* [ns..ns + len) should be a string with the id of the rtx to match
+ i.e. if rtx is the relevant match_operand or match_scratch then
+ [ns..ns + len) should equal itoa (XINT (rtx, 0)), and if set_attr then
+ [ns..ns + len) should equal XSTR (rtx, 0). */
+ conlist (const char *ns, unsigned int len, bool numeric)
+ {
+ /* Trim leading whitespaces. */
+ while (ISBLANK (*ns))
+ {
+ ns++;
+ len--;
+ }
+
+ /* Trim trailing whitespace. */
+ for (int i = len - 1; i >= 0; i--, len--)
+ if (!ISBLANK (ns[i]))
+ break;
+
+ /* Parse off any modifiers. */
+ while (!ISALNUM (*ns))
+ {
+ con += *(ns++);
+ len--;
+ }
+
+ name.assign (ns, len);
+ if (numeric)
+ idx = std::stoi (name);
+ }
+
+ /* Adds a character to the end of the string. */
+ void add (char c)
+ {
+ con += c;
+ }
+
+ /* Output the string in the form of a brand-new char *, then effectively
+ clear the internal string by resetting len to 0. */
+ char *out ()
+ {
+ /* Final character is always a trailing comma, so strip it out. */
+ char *q = xstrndup (con.c_str (), con.size () - 1);
+ con.clear ();
+ return q;
+ }
+};
+
+typedef std::vector<conlist> vec_conlist;
+
+/* Add constraints to an rtx. This function is similar to remove_constraints.
+ Errors if adding the constraints would overwrite existing constraints. */
+
+static void
+add_constraints (rtx part, file_location loc, vec_conlist &cons)
+{
+ const char *format_ptr;
+
+ if (part == NULL_RTX)
+ return;
+
+ /* If match_op or match_scr, check if we have the right one, and if so, copy
+ over the constraint list. */
+ if (GET_CODE (part) == MATCH_OPERAND || GET_CODE (part) == MATCH_SCRATCH)
+ {
+ int field = GET_CODE (part) == MATCH_OPERAND ? 2 : 1;
+ unsigned id = XINT (part, 0);
+
+ if (id >= cons.size ())
+ fatal_at (loc, "could not find match_operand/scratch with id %d", id);
+
+ if (cons[id].idx == -1)
+ return;
+
+ if (XSTR (part, field)[0] != '\0')
+ {
+ error_at (loc, "can't mix normal and compact constraint syntax");
+ return;
+ }
+ XSTR (part, field) = cons[id].out ();
+ cons[id].idx = -1;
+ }
+
+ format_ptr = GET_RTX_FORMAT (GET_CODE (part));
+
+ /* Recursively search the rtx. */
+ for (int i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++)
+ switch (*format_ptr++)
+ {
+ case 'e':
+ case 'u':
+ add_constraints (XEXP (part, i), loc, cons);
+ break;
+ case 'E':
+ if (XVEC (part, i) != NULL)
+ for (int j = 0; j < XVECLEN (part, i); j++)
+ add_constraints (XVECEXP (part, i, j), loc, cons);
+ break;
+ default:
+ continue;
+ }
+}
+
+/* Add ATTRS to definition X's attribute list. */
+
+static void
+add_attributes (rtx x, vec_conlist &attrs)
+{
+ unsigned int attr_index = GET_CODE (x) == DEFINE_INSN ? 4 : 3;
+ rtvec orig = XVEC (x, attr_index);
+ size_t n_curr = orig ? XVECLEN (x, attr_index) : 0;
+ rtvec copy = rtvec_alloc (n_curr + attrs.size ());
+
+ /* Create a shallow copy of existing entries. */
+ memcpy (©->elem[attrs.size ()], &orig->elem[0], sizeof (rtx) * n_curr);
+ XVEC (x, attr_index) = copy;
+
+ /* Create the new elements. */
+ for (unsigned i = 0; i < attrs.size (); i++)
+ {
+ rtx attr = rtx_alloc (SET_ATTR);
+ XSTR (attr, 0) = xstrdup (attrs[i].name.c_str ());
+ XSTR (attr, 1) = attrs[i].out ();
+ XVECEXP (x, attr_index, i) = attr;
+ }
+}
+
+/* Consumes spaces and tabs. */
+
+static inline void
+skip_spaces (const char **str)
+{
+ while (ISBLANK (**str))
+ (*str)++;
+}
+
+/* Consumes the given character, if it's there. */
+
+static inline bool
+expect_char (const char **str, char c)
+{
+ if (**str != c)
+ return false;
+ (*str)++;
+ return true;
+}
+
+/* Parses the section layout that follows a "{@" if using new syntax. Builds
+ a vector for a single section. E.g. if we have "attrs: length, arch]..."
+ then list will have two elements, the first for "length" and the second
+ for "arch". */
+
+static void
+parse_section_layout (file_location loc, const char **templ, const char *label,
+ vec_conlist &list, bool numeric)
+{
+ const char *name_start;
+ size_t label_len = strlen (label);
+ if (strncmp (label, *templ, label_len) == 0)
+ {
+ *templ += label_len;
+
+ /* Gather the names. */
+ while (**templ != ';' && **templ != ']')
+ {
+ skip_spaces (templ);
+ name_start = *templ;
+ int len = 0;
+ char val = (*templ)[len];
+ while (val != ',' && val != ';' && val != ']')
+ {
+ if (val == 0 || val == '\n')
+ fatal_at (loc, "missing ']'");
+ val = (*templ)[++len];
+ }
+ *templ += len;
+ if (val == ',')
+ (*templ)++;
+ list.push_back (conlist (name_start, len, numeric));
+ }
+ }
+}
+
+/* Parse a section, a section is defined as a named space separated list, e.g.
+
+ foo: a, b, c
+
+ is a section named "foo" with entries a, b and c. */
+
+static void
+parse_section (const char **templ, unsigned int n_elems, unsigned int alt_no,
+ vec_conlist &list, file_location loc, const char *name)
+{
+ unsigned int i;
+
+ /* Go through the list, one character at a time, adding said character
+ to the correct string. */
+ for (i = 0; **templ != ']' && **templ != ';'; (*templ)++)
+ if (!ISBLANK (**templ))
+ {
+ list[i].add (**templ);
+ if (**templ == ',')
+ {
+ ++i;
+ if (i == n_elems)
+ fatal_at (loc, "too many %ss in alternative %d: expected %d",
+ name, alt_no, n_elems);
+ }
+ if (**templ == 0 || **templ == '\n')
+ fatal_at (loc, "missing ']'");
+ }
+
+ if (i + 1 < n_elems)
+ fatal_at (loc, "too few %ss in alternative %d: expected %d, got %d",
+ name, alt_no, n_elems, i);
+
+ list[i].add (',');
+}
+
+/* The compact syntax has more convience syntaxes. As such we post process
+ the lines to get them back to something the normal syntax understands. */
+
+static void
+preprocess_compact_syntax (file_location loc, int alt_no, std::string &line,
+ std::string &last_line)
+{
+ /* Check if we're copying the last statement. */
+ if (line.find ("^") == 0 && line.size () == 1)
+ {
+ if (last_line.empty ())
+ fatal_at (loc, "found instruction to copy previous line (^) in"
+ "alternative %d but no previous line to copy", alt_no);
+ line = last_line;
+ return;
+ }
+
+ std::string result;
+ std::string buffer;
+ /* Check if we have << which means return c statement. */
+ if (line.find ("<<") == 0)
+ {
+ result.append ("* return ");
+ const char *chunk = line.c_str () + 2;
+ skip_spaces (&chunk);
+ result.append (chunk);
+ }
+ else
+ result.append (line);
+
+ line = result;
+ return;
+}
+
+/* Converts an rtx from compact syntax to normal syntax if possible. */
+
+static void
+convert_syntax (rtx x, file_location loc)
+{
+ int alt_no;
+ unsigned int templ_index;
+ const char *templ;
+ vec_conlist tconvec, convec, attrvec;
+
+ templ_index = GET_CODE (x) == DEFINE_INSN ? 3 : 2;
+
+ templ = XTMPL (x, templ_index);
+
+ /* Templates with constraints start with "{@". */
+ if (strncmp ("*{@", templ, 3))
+ return;
+
+ /* Get the layout for the template. */
+ templ += 3;
+ skip_spaces (&templ);
+
+ if (!expect_char (&templ, '['))
+ fatal_at (loc, "expecing `[' to begin section list");
+
+ parse_section_layout (loc, &templ, "cons:", tconvec, true);
+ convec.resize (tconvec.size ());
+
+ /* Check for any duplicate cons entries and sort based on i. */
+ for (auto e : tconvec)
+ {
+ unsigned idx = e.idx;
+ if (idx >= convec.size ())
+ convec.resize (idx + 1);
+
+ if (convec[idx].idx >= 0)
+ fatal_at (loc, "duplicate cons number found: %d", idx);
+ convec[idx] = e;
+ }
+ tconvec.clear ();
+
+ if (*templ != ']')
+ {
+ if (*templ == ';')
+ skip_spaces (&(++templ));
+ parse_section_layout (loc, &templ, "attrs:", attrvec, false);
+ }
+
+ if (!expect_char (&templ, ']'))
+ fatal_at (loc, "expecting `]` to end section list - section list must have "
+ "cons first, attrs second");
+
+ /* We will write the un-constrainified template into new_templ. */
+ std::string new_templ;
+ new_templ.append ("@");
+
+ /* Skip to the first proper line. */
+ while (*templ++ != '\n');
+
+ alt_no = 0;
+ std::string last_line;
+
+ /* Process the alternatives. */
+ while (*(templ - 1) != '\0')
+ {
+ /* Skip leading whitespace. */
+ std::string buffer;
+ skip_spaces (&templ);
+
+ /* Check if we're at the end. */
+ if (templ[0] == '}' && templ[1] == '\0')
+ break;
+
+ if (expect_char (&templ, '['))
+ {
+ new_templ += '\n';
+ new_templ.append (buffer);
+ /* Parse the constraint list, then the attribute list. */
+ if (convec.size () > 0)
+ parse_section (&templ, convec.size (), alt_no, convec, loc,
+ "constraint");
+
+ if (attrvec.size () > 0)
+ {
+ if (convec.size () > 0 && !expect_char (&templ, ';'))
+ fatal_at (loc, "expected `;' to separate constraints "
+ "and attributes in alternative %d", alt_no);
+
+ parse_section (&templ, attrvec.size (), alt_no,
+ attrvec, loc, "attribute");
+ }
+
+ if (!expect_char (&templ, ']'))
+ fatal_at (loc, "expected end of constraint/attribute list but "
+ "missing an ending `]' in alternative %d", alt_no);
+ }
+ else if (templ[0] == '/' && templ[1] == '/')
+ {
+ templ += 2;
+ /* Glob till newline or end of string. */
+ while (*templ != '\n' || *templ != '\0')
+ templ++;
+ templ++;
+
+ /* Skip any newlines or whitespaces needed. */
+ while (ISSPACE(*templ))
+ templ++;
+ continue;
+ }
+ else if (templ[0] == '/' && templ[1] == '*')
+ {
+ templ += 2;
+ /* Glob till newline or end of multiline comment. */
+ while (templ[0] != 0 && templ[0] != '*' && templ[1] != '/')
+ templ++;
+ templ += 2;
+
+ /* Skip any newlines or whitespaces needed. */
+ while (ISSPACE(*templ))
+ templ++;
+ continue;
+ }
+ else
+ fatal_at (loc, "expected constraint/attribute list at beginning of "
+ "alternative %d but missing a starting `['", alt_no);
+
+ /* Skip whitespace between list and asm. */
+ ++templ;
+ skip_spaces (&templ);
+
+ /* Copy asm to new template. */
+ std::string line;
+ while (*templ != '\n' && *templ != '\0')
+ line += *templ++;
+
+ /* Apply any pre-processing needed to the line. */
+ preprocess_compact_syntax (loc, alt_no, line, last_line);
+ new_templ.append (line);
+ last_line = line;
+
+ /* Normal "*..." syntax expects the closing quote to be on the final
+ line of asm, whereas we allow the closing "}" to be on its own line.
+ Postpone copying the '\n' until we know that there is another
+ alternative in the list. */
+ while (ISSPACE (*templ))
+ templ++;
+ ++alt_no;
+ }
+
+ /* Write the constraints and attributes into their proper places. */
+ if (convec.size () > 0)
+ add_constraints (x, loc, convec);
+
+ if (attrvec.size () > 0)
+ add_attributes (x, attrvec);
+
+ /* Copy over the new un-constrainified template. */
+ XTMPL (x, templ_index) = xstrdup (new_templ.c_str ());
+
+ /* Register for later checks during iterator expansions. */
+ compact_syntax.add (x);
+}
+
/* Process a top level rtx in some way, queuing as appropriate. */
static void
@@ -553,10 +1036,12 @@ process_rtx (rtx desc, file_location loc)
switch (GET_CODE (desc))
{
case DEFINE_INSN:
+ convert_syntax (desc, loc);
queue_pattern (desc, &define_insn_tail, loc);
break;
case DEFINE_COND_EXEC:
+ convert_syntax (desc, loc);
queue_pattern (desc, &define_cond_exec_tail, loc);
break;
@@ -631,6 +1116,7 @@ process_rtx (rtx desc, file_location loc)
attr = XVEC (desc, split_code + 1);
PUT_CODE (desc, DEFINE_INSN);
XVEC (desc, 4) = attr;
+ convert_syntax (desc, loc);
/* Queue them. */
insn_elem = queue_pattern (desc, &define_insn_tail, loc);
[-- Attachment #2: rb17151.patch --]
[-- Type: application/octet-stream, Size: 23303 bytes --]
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 6a435eb44610960513e9739ac9ac1e8a27182c10..3bd1bcbc8beda9bbaea71c65118ecfa2cdace335 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -27,6 +27,7 @@ See the next chapter for information on the C header file.
from such an insn.
* Output Statement:: For more generality, write C code to output
the assembler code.
+* Compact Syntax:: Compact syntax for writing machine descriptors.
* Predicates:: Controlling what kinds of operands can be used
for an insn.
* Constraints:: Fine-tuning operand selection.
@@ -713,6 +714,167 @@ you can use @samp{*} inside of a @samp{@@} multi-alternative template:
@end group
@end smallexample
+@node Compact Syntax
+@section Compact Syntax
+@cindex compact syntax
+
+When a @code{define_insn} or @code{define_insn_and_split} has multiple
+alternatives it may be beneficial to use the compact syntax when specifying
+alternatives.
+
+This syntax puts the constraints and attributes on the same horizontal line as
+the instruction assembly template.
+
+As an example
+
+@smallexample
+@group
+(define_insn_and_split ""
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,k,r,r,r,r")
+ (match_operand:SI 1 "aarch64_mov_operand" " r,r,k,M,n,Usv"))]
+ ""
+ "@@
+ mov\\t%w0, %w1
+ mov\\t%w0, %w1
+ mov\\t%w0, %w1
+ mov\\t%w0, %1
+ #
+ * return aarch64_output_sve_cnt_immediate ('cnt', '%x0', operands[1]);"
+ "&& true"
+ [(const_int 0)]
+ @{
+ aarch64_expand_mov_immediate (operands[0], operands[1]);
+ DONE;
+ @}
+ [(set_attr "type" "mov_reg,mov_reg,mov_reg,mov_imm,mov_imm,mov_imm")
+ (set_attr "arch" "*,*,*,*,*,sve")
+ (set_attr "length" "4,4,4,4,*, 4")
+]
+)
+@end group
+@end smallexample
+
+can be better expressed as:
+
+@smallexample
+@group
+(define_insn_and_split ""
+ [(set (match_operand:SI 0 "nonimmediate_operand")
+ (match_operand:SI 1 "aarch64_mov_operand"))]
+ ""
+ @{@@ [cons: =0, 1; attrs: type, arch, length]
+ [r , r ; mov_reg , * , 4] mov\t%w0, %w1
+ [k , r ; mov_reg , * , 4] ^
+ [r , k ; mov_reg , * , 4] ^
+ [r , M ; mov_imm , * , 4] mov\t%w0, %1
+ [r , n ; mov_imm , * , *] #
+ [r , Usv; mov_imm , sve , 4] << aarch64_output_sve_cnt_immediate ("cnt", "%x0", operands[1]);
+ @}
+ "&& true"
+ [(const_int 0)]
+ @{
+ aarch64_expand_mov_immediate (operands[0], operands[1]);
+ DONE;
+ @}
+)
+@end group
+@end smallexample
+
+The syntax rules are as follows:
+@itemize @bullet
+@item
+Templates must start with @samp{@{@@} to use the new syntax.
+
+@item
+@samp{@{@@} is followed by a layout in parentheses which is @samp{cons:}
+followed by a comma-separated list of @code{match_operand}/@code{match_scratch}
+operand numbers, then a semicolon, followed by the same for attributes
+(@samp{attrs:}). Operand modifiers can be placed in this section group as well.
+Both sections are optional (so you can use only @samp{cons}, or only
+@samp{attrs}, or both), and @samp{cons} must come before @samp{attrs} if
+present.
+
+@item
+Each alternative begins with any amount of whitespace.
+
+@item
+Following the whitespace is a comma-separated list of "constraints" and/or
+"attributes" within brackets @code{[]}, with sections separated by a semicolon.
+
+@item
+Should you want to copy the previous asm line, the symbol @code{^} can be used.
+This allows less copy pasting between alternative and reduces the number of
+lines to update on changes.
+
+@item
+When using C functions for output, the idiom @samp{* return @var{function};}
+can be replaced with the shorthand @samp{<< @var{function};}.
+
+@item
+Following the closing @samp{]} is any amount of whitespace, and then the actual
+asm output.
+
+@item
+Spaces are allowed in the list (they will simply be removed).
+
+@item
+All constraint alternatives should be specified. For example, a list of
+of three blank alternatives should be written @samp{[,,]} rather than
+@samp{[]}.
+
+@item
+All attribute alternatives should be non-empty, with @samp{*}
+representing the default attribute value. For example, a list of three
+default attribute values should be written @samp{[*,*,*]} rather than
+@samp{[]}.
+
+
+@item
+Within an @samp{@{@@} block both multiline and singleline C comments are
+allowed, but when used outside of a C block they must be the only non-whitespace
+blocks on the line.
+
+@item
+Within an @samp{@{@@} block, any iterators that do not get expanded will result
+in an error. If for some reason it is required to have @code{<} or @code{>} in
+the output then these must be escaped using @backslashchar{}.
+
+@item
+It is possible to use the @samp{attrs} list to specify some attributes and to
+use the normal @code{set_attr} syntax to specify other attributes. There must
+not be any overlap between the two lists.
+
+In other words, the following is valid:
+@smallexample
+@group
+(define_insn_and_split ""
+ [(set (match_operand:SI 0 "nonimmediate_operand")
+ (match_operand:SI 1 "aarch64_mov_operand"))]
+ ""
+ @{@@ [cons: 0, 1; attrs: type, arch, length]@}
+ @dots{}
+ [(set_attr "foo" "mov_imm")]
+)
+@end group
+@end smallexample
+
+but this is not valid:
+@smallexample
+@group
+(define_insn_and_split ""
+ [(set (match_operand:SI 0 "nonimmediate_operand")
+ (match_operand:SI 1 "aarch64_mov_operand"))]
+ ""
+ @{@@ [cons: 0, 1; attrs: type, arch, length]@}
+ @dots{}
+ [(set_attr "arch" "bar")
+ (set_attr "foo" "mov_imm")]
+)
+@end group
+@end smallexample
+
+because you can't mix and match new and old syntax.
+
@node Predicates
@section Predicates
@cindex predicates
diff --git a/gcc/genoutput.cc b/gcc/genoutput.cc
index 163e8dfef4ca2c2c92ce1cf001ee6be40a54ca3e..3fbdde70df30d23a11b23d59eefe95b86f148c76 100644
--- a/gcc/genoutput.cc
+++ b/gcc/genoutput.cc
@@ -157,6 +157,7 @@ public:
int n_alternatives; /* Number of alternatives in each constraint */
int operand_number; /* Operand index in the big array. */
int output_format; /* INSN_OUTPUT_FORMAT_*. */
+ bool compact_syntax_p;
struct operand_data operand[MAX_MAX_OPERANDS];
};
@@ -700,12 +701,51 @@ process_template (class data *d, const char *template_code)
if (sp != ep)
message_at (d->loc, "trailing whitespace in output template");
- while (cp < sp)
+ /* Check for any unexpanded iterators. */
+ if (bp[0] != '*' && d->compact_syntax_p)
{
- putchar (*cp);
- cp++;
+ const char *p = cp;
+ const char *last_bracket = nullptr;
+ while (p < sp)
+ {
+ if (*p == '\\' && p + 1 < sp)
+ {
+ putchar (*p);
+ putchar (*(p+1));
+ p += 2;
+ continue;
+ }
+
+ if (*p == '>' && last_bracket && *last_bracket == '<')
+ {
+ int len = p - last_bracket;
+ fatal_at (d->loc, "unresolved iterator '%.*s' in '%s'",
+ len - 1, last_bracket + 1, cp);
+ }
+ else if (*p == '<' || *p == '>')
+ last_bracket = p;
+
+ putchar (*p);
+ p += 1;
+ }
+
+ if (last_bracket)
+ {
+ char *nl = strchr (const_cast<char*> (cp), '\n');
+ if (nl)
+ *nl = '\0';
+ fatal_at (d->loc, "unmatched angle brackets, likely an "
+ "error in iterator syntax in %s", cp);
+ }
+ }
+ else
+ {
+ while (cp < sp)
+ putchar (*(cp++));
}
+ cp = sp;
+
if (!found_star)
puts ("\",");
else if (*bp != '*')
@@ -881,6 +921,8 @@ gen_insn (md_rtx_info *info)
else
d->name = 0;
+ d->compact_syntax_p = compact_syntax.contains (insn);
+
/* Build up the list in the same order as the insns are seen
in the machine description. */
d->next = 0;
diff --git a/gcc/gensupport.h b/gcc/gensupport.h
index a1edfbd71908b6244b40f801c6c01074de56777e..7925e22ed418767576567cad583bddf83c0846b1 100644
--- a/gcc/gensupport.h
+++ b/gcc/gensupport.h
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_GENSUPPORT_H
#define GCC_GENSUPPORT_H
+#include "hash-set.h"
#include "read-md.h"
struct obstack;
@@ -218,6 +219,8 @@ struct pattern_stats
int num_operand_vars;
};
+extern hash_set<rtx> compact_syntax;
+
extern void get_pattern_stats (struct pattern_stats *ranges, rtvec vec);
extern void compute_test_codes (rtx, file_location, char *);
extern file_location get_file_location (rtx);
diff --git a/gcc/gensupport.cc b/gcc/gensupport.cc
index f9efc6eb7572a44b8bb154b0b22be3815bd0d244..7b704284153f3702bc023194d9ef394d8722c3bd 100644
--- a/gcc/gensupport.cc
+++ b/gcc/gensupport.cc
@@ -18,6 +18,8 @@
<http://www.gnu.org/licenses/>. */
#include "bconfig.h"
+#define INCLUDE_STRING
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tm.h"
@@ -33,6 +35,8 @@
static rtx operand_data[MAX_OPERANDS];
static rtx match_operand_entries_in_pattern[MAX_OPERANDS];
static char used_operands_numbers[MAX_OPERANDS];
+/* List of entries which are part of the new syntax. */
+hash_set<rtx> compact_syntax;
/* In case some macros used by files we include need it, define this here. */
@@ -545,6 +549,485 @@ gen_rewrite_sequence (rtvec vec)
return new_vec;
}
+/* The following is for handling the compact syntax for constraints and
+ attributes.
+
+ The normal syntax looks like this:
+
+ ...
+ (match_operand: 0 "s_register_operand" "r,I,k")
+ (match_operand: 2 "s_register_operand" "r,k,I")
+ ...
+ "@
+ <asm>
+ <asm>
+ <asm>"
+ ...
+ (set_attr "length" "4,8,8")
+
+ The compact syntax looks like this:
+
+ ...
+ (match_operand: 0 "s_register_operand")
+ (match_operand: 2 "s_register_operand")
+ ...
+ {@ [cons: 0, 2; attrs: length]
+ [r,r; 4] <asm>
+ [I,k; 8] <asm>
+ [k,I; 8] <asm>
+ }
+ ...
+ [<other attributes>]
+
+ This is the only place where this syntax needs to be handled. Relevant
+ patterns are transformed from compact to the normal syntax before they are
+ queued, so none of the gen* programs need to know about this syntax at all.
+
+ Conversion process (convert_syntax):
+
+ 0) Check that pattern actually uses new syntax (check for {@ ... }).
+
+ 1) Get the "layout", i.e. the "[cons: 0 2; attrs: length]" from the above
+ example. cons must come first; both are optional. Set up two vecs,
+ convec and attrvec, for holding the results of the transformation.
+
+ 2) For each alternative: parse the list of constraints and/or attributes,
+ and enqueue them in the relevant lists in convec and attrvec. By the end
+ of this process, convec[N].con and attrvec[N].con should contain regular
+ syntax constraint/attribute lists like "r,I,k". Copy the asm to a string
+ as we go.
+
+ 3) Search the rtx and write the constraint and attribute lists into the
+ correct places. Write the asm back into the template. */
+
+/* Helper class for shuffling constraints/attributes in convert_syntax and
+ add_constraints/add_attributes. This includes commas but not whitespace. */
+
+class conlist {
+private:
+ std::string con;
+
+public:
+ std::string name;
+ int idx = -1;
+
+ conlist () = default;
+
+ /* [ns..ns + len) should be a string with the id of the rtx to match
+ i.e. if rtx is the relevant match_operand or match_scratch then
+ [ns..ns + len) should equal itoa (XINT (rtx, 0)), and if set_attr then
+ [ns..ns + len) should equal XSTR (rtx, 0). */
+ conlist (const char *ns, unsigned int len, bool numeric)
+ {
+ /* Trim leading whitespaces. */
+ while (ISBLANK (*ns))
+ {
+ ns++;
+ len--;
+ }
+
+ /* Trim trailing whitespace. */
+ for (int i = len - 1; i >= 0; i--, len--)
+ if (!ISBLANK (ns[i]))
+ break;
+
+ /* Parse off any modifiers. */
+ while (!ISALNUM (*ns))
+ {
+ con += *(ns++);
+ len--;
+ }
+
+ name.assign (ns, len);
+ if (numeric)
+ idx = std::stoi (name);
+ }
+
+ /* Adds a character to the end of the string. */
+ void add (char c)
+ {
+ con += c;
+ }
+
+ /* Output the string in the form of a brand-new char *, then effectively
+ clear the internal string by resetting len to 0. */
+ char *out ()
+ {
+ /* Final character is always a trailing comma, so strip it out. */
+ char *q = xstrndup (con.c_str (), con.size () - 1);
+ con.clear ();
+ return q;
+ }
+};
+
+typedef std::vector<conlist> vec_conlist;
+
+/* Add constraints to an rtx. This function is similar to remove_constraints.
+ Errors if adding the constraints would overwrite existing constraints. */
+
+static void
+add_constraints (rtx part, file_location loc, vec_conlist &cons)
+{
+ const char *format_ptr;
+
+ if (part == NULL_RTX)
+ return;
+
+ /* If match_op or match_scr, check if we have the right one, and if so, copy
+ over the constraint list. */
+ if (GET_CODE (part) == MATCH_OPERAND || GET_CODE (part) == MATCH_SCRATCH)
+ {
+ int field = GET_CODE (part) == MATCH_OPERAND ? 2 : 1;
+ unsigned id = XINT (part, 0);
+
+ if (id >= cons.size ())
+ fatal_at (loc, "could not find match_operand/scratch with id %d", id);
+
+ if (cons[id].idx == -1)
+ return;
+
+ if (XSTR (part, field)[0] != '\0')
+ {
+ error_at (loc, "can't mix normal and compact constraint syntax");
+ return;
+ }
+ XSTR (part, field) = cons[id].out ();
+ cons[id].idx = -1;
+ }
+
+ format_ptr = GET_RTX_FORMAT (GET_CODE (part));
+
+ /* Recursively search the rtx. */
+ for (int i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++)
+ switch (*format_ptr++)
+ {
+ case 'e':
+ case 'u':
+ add_constraints (XEXP (part, i), loc, cons);
+ break;
+ case 'E':
+ if (XVEC (part, i) != NULL)
+ for (int j = 0; j < XVECLEN (part, i); j++)
+ add_constraints (XVECEXP (part, i, j), loc, cons);
+ break;
+ default:
+ continue;
+ }
+}
+
+/* Add ATTRS to definition X's attribute list. */
+
+static void
+add_attributes (rtx x, vec_conlist &attrs)
+{
+ unsigned int attr_index = GET_CODE (x) == DEFINE_INSN ? 4 : 3;
+ rtvec orig = XVEC (x, attr_index);
+ size_t n_curr = orig ? XVECLEN (x, attr_index) : 0;
+ rtvec copy = rtvec_alloc (n_curr + attrs.size ());
+
+ /* Create a shallow copy of existing entries. */
+ memcpy (©->elem[attrs.size ()], &orig->elem[0], sizeof (rtx) * n_curr);
+ XVEC (x, attr_index) = copy;
+
+ /* Create the new elements. */
+ for (unsigned i = 0; i < attrs.size (); i++)
+ {
+ rtx attr = rtx_alloc (SET_ATTR);
+ XSTR (attr, 0) = xstrdup (attrs[i].name.c_str ());
+ XSTR (attr, 1) = attrs[i].out ();
+ XVECEXP (x, attr_index, i) = attr;
+ }
+}
+
+/* Consumes spaces and tabs. */
+
+static inline void
+skip_spaces (const char **str)
+{
+ while (ISBLANK (**str))
+ (*str)++;
+}
+
+/* Consumes the given character, if it's there. */
+
+static inline bool
+expect_char (const char **str, char c)
+{
+ if (**str != c)
+ return false;
+ (*str)++;
+ return true;
+}
+
+/* Parses the section layout that follows a "{@" if using new syntax. Builds
+ a vector for a single section. E.g. if we have "attrs: length, arch]..."
+ then list will have two elements, the first for "length" and the second
+ for "arch". */
+
+static void
+parse_section_layout (file_location loc, const char **templ, const char *label,
+ vec_conlist &list, bool numeric)
+{
+ const char *name_start;
+ size_t label_len = strlen (label);
+ if (strncmp (label, *templ, label_len) == 0)
+ {
+ *templ += label_len;
+
+ /* Gather the names. */
+ while (**templ != ';' && **templ != ']')
+ {
+ skip_spaces (templ);
+ name_start = *templ;
+ int len = 0;
+ char val = (*templ)[len];
+ while (val != ',' && val != ';' && val != ']')
+ {
+ if (val == 0 || val == '\n')
+ fatal_at (loc, "missing ']'");
+ val = (*templ)[++len];
+ }
+ *templ += len;
+ if (val == ',')
+ (*templ)++;
+ list.push_back (conlist (name_start, len, numeric));
+ }
+ }
+}
+
+/* Parse a section, a section is defined as a named space separated list, e.g.
+
+ foo: a, b, c
+
+ is a section named "foo" with entries a, b and c. */
+
+static void
+parse_section (const char **templ, unsigned int n_elems, unsigned int alt_no,
+ vec_conlist &list, file_location loc, const char *name)
+{
+ unsigned int i;
+
+ /* Go through the list, one character at a time, adding said character
+ to the correct string. */
+ for (i = 0; **templ != ']' && **templ != ';'; (*templ)++)
+ if (!ISBLANK (**templ))
+ {
+ list[i].add (**templ);
+ if (**templ == ',')
+ {
+ ++i;
+ if (i == n_elems)
+ fatal_at (loc, "too many %ss in alternative %d: expected %d",
+ name, alt_no, n_elems);
+ }
+ if (**templ == 0 || **templ == '\n')
+ fatal_at (loc, "missing ']'");
+ }
+
+ if (i + 1 < n_elems)
+ fatal_at (loc, "too few %ss in alternative %d: expected %d, got %d",
+ name, alt_no, n_elems, i);
+
+ list[i].add (',');
+}
+
+/* The compact syntax has more convience syntaxes. As such we post process
+ the lines to get them back to something the normal syntax understands. */
+
+static void
+preprocess_compact_syntax (file_location loc, int alt_no, std::string &line,
+ std::string &last_line)
+{
+ /* Check if we're copying the last statement. */
+ if (line.find ("^") == 0 && line.size () == 1)
+ {
+ if (last_line.empty ())
+ fatal_at (loc, "found instruction to copy previous line (^) in"
+ "alternative %d but no previous line to copy", alt_no);
+ line = last_line;
+ return;
+ }
+
+ std::string result;
+ std::string buffer;
+ /* Check if we have << which means return c statement. */
+ if (line.find ("<<") == 0)
+ {
+ result.append ("* return ");
+ const char *chunk = line.c_str () + 2;
+ skip_spaces (&chunk);
+ result.append (chunk);
+ }
+ else
+ result.append (line);
+
+ line = result;
+ return;
+}
+
+/* Converts an rtx from compact syntax to normal syntax if possible. */
+
+static void
+convert_syntax (rtx x, file_location loc)
+{
+ int alt_no;
+ unsigned int templ_index;
+ const char *templ;
+ vec_conlist tconvec, convec, attrvec;
+
+ templ_index = GET_CODE (x) == DEFINE_INSN ? 3 : 2;
+
+ templ = XTMPL (x, templ_index);
+
+ /* Templates with constraints start with "{@". */
+ if (strncmp ("*{@", templ, 3))
+ return;
+
+ /* Get the layout for the template. */
+ templ += 3;
+ skip_spaces (&templ);
+
+ if (!expect_char (&templ, '['))
+ fatal_at (loc, "expecing `[' to begin section list");
+
+ parse_section_layout (loc, &templ, "cons:", tconvec, true);
+ convec.resize (tconvec.size ());
+
+ /* Check for any duplicate cons entries and sort based on i. */
+ for (auto e : tconvec)
+ {
+ unsigned idx = e.idx;
+ if (idx >= convec.size ())
+ convec.resize (idx + 1);
+
+ if (convec[idx].idx >= 0)
+ fatal_at (loc, "duplicate cons number found: %d", idx);
+ convec[idx] = e;
+ }
+ tconvec.clear ();
+
+ if (*templ != ']')
+ {
+ if (*templ == ';')
+ skip_spaces (&(++templ));
+ parse_section_layout (loc, &templ, "attrs:", attrvec, false);
+ }
+
+ if (!expect_char (&templ, ']'))
+ fatal_at (loc, "expecting `]` to end section list - section list must have "
+ "cons first, attrs second");
+
+ /* We will write the un-constrainified template into new_templ. */
+ std::string new_templ;
+ new_templ.append ("@");
+
+ /* Skip to the first proper line. */
+ while (*templ++ != '\n');
+
+ alt_no = 0;
+ std::string last_line;
+
+ /* Process the alternatives. */
+ while (*(templ - 1) != '\0')
+ {
+ /* Skip leading whitespace. */
+ std::string buffer;
+ skip_spaces (&templ);
+
+ /* Check if we're at the end. */
+ if (templ[0] == '}' && templ[1] == '\0')
+ break;
+
+ if (expect_char (&templ, '['))
+ {
+ new_templ += '\n';
+ new_templ.append (buffer);
+ /* Parse the constraint list, then the attribute list. */
+ if (convec.size () > 0)
+ parse_section (&templ, convec.size (), alt_no, convec, loc,
+ "constraint");
+
+ if (attrvec.size () > 0)
+ {
+ if (convec.size () > 0 && !expect_char (&templ, ';'))
+ fatal_at (loc, "expected `;' to separate constraints "
+ "and attributes in alternative %d", alt_no);
+
+ parse_section (&templ, attrvec.size (), alt_no,
+ attrvec, loc, "attribute");
+ }
+
+ if (!expect_char (&templ, ']'))
+ fatal_at (loc, "expected end of constraint/attribute list but "
+ "missing an ending `]' in alternative %d", alt_no);
+ }
+ else if (templ[0] == '/' && templ[1] == '/')
+ {
+ templ += 2;
+ /* Glob till newline or end of string. */
+ while (*templ != '\n' || *templ != '\0')
+ templ++;
+ templ++;
+
+ /* Skip any newlines or whitespaces needed. */
+ while (ISSPACE(*templ))
+ templ++;
+ continue;
+ }
+ else if (templ[0] == '/' && templ[1] == '*')
+ {
+ templ += 2;
+ /* Glob till newline or end of multiline comment. */
+ while (templ[0] != 0 && templ[0] != '*' && templ[1] != '/')
+ templ++;
+ templ += 2;
+
+ /* Skip any newlines or whitespaces needed. */
+ while (ISSPACE(*templ))
+ templ++;
+ continue;
+ }
+ else
+ fatal_at (loc, "expected constraint/attribute list at beginning of "
+ "alternative %d but missing a starting `['", alt_no);
+
+ /* Skip whitespace between list and asm. */
+ ++templ;
+ skip_spaces (&templ);
+
+ /* Copy asm to new template. */
+ std::string line;
+ while (*templ != '\n' && *templ != '\0')
+ line += *templ++;
+
+ /* Apply any pre-processing needed to the line. */
+ preprocess_compact_syntax (loc, alt_no, line, last_line);
+ new_templ.append (line);
+ last_line = line;
+
+ /* Normal "*..." syntax expects the closing quote to be on the final
+ line of asm, whereas we allow the closing "}" to be on its own line.
+ Postpone copying the '\n' until we know that there is another
+ alternative in the list. */
+ while (ISSPACE (*templ))
+ templ++;
+ ++alt_no;
+ }
+
+ /* Write the constraints and attributes into their proper places. */
+ if (convec.size () > 0)
+ add_constraints (x, loc, convec);
+
+ if (attrvec.size () > 0)
+ add_attributes (x, attrvec);
+
+ /* Copy over the new un-constrainified template. */
+ XTMPL (x, templ_index) = xstrdup (new_templ.c_str ());
+
+ /* Register for later checks during iterator expansions. */
+ compact_syntax.add (x);
+}
+
/* Process a top level rtx in some way, queuing as appropriate. */
static void
@@ -553,10 +1036,12 @@ process_rtx (rtx desc, file_location loc)
switch (GET_CODE (desc))
{
case DEFINE_INSN:
+ convert_syntax (desc, loc);
queue_pattern (desc, &define_insn_tail, loc);
break;
case DEFINE_COND_EXEC:
+ convert_syntax (desc, loc);
queue_pattern (desc, &define_cond_exec_tail, loc);
break;
@@ -631,6 +1116,7 @@ process_rtx (rtx desc, file_location loc)
attr = XVEC (desc, split_code + 1);
PUT_CODE (desc, DEFINE_INSN);
XVEC (desc, 4) = attr;
+ convert_syntax (desc, loc);
/* Queue them. */
insn_elem = queue_pattern (desc, &define_insn_tail, loc);
next prev parent reply other threads:[~2023-06-13 15:27 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-04-18 16:30 [PATCH] RFC: " Tamar Christina
2023-04-21 17:18 ` Richard Sandiford
2023-04-24 8:33 ` Richard Sandiford
2023-05-16 13:56 ` Richard Earnshaw (lists)
2023-04-24 9:05 ` Tamar Christina
2023-04-24 9:37 ` Richard Sandiford
2023-06-05 13:51 ` [PATCH v2] machine descriptor: " Tamar Christina
2023-06-05 20:35 ` Richard Sandiford
2023-06-06 7:47 ` Richard Sandiford
2023-06-06 12:00 ` Tamar Christina
2023-06-06 12:49 ` Richard Sandiford
2023-06-06 16:13 ` Richard Earnshaw (lists)
2023-06-08 9:58 ` Tamar Christina
2023-06-08 10:12 ` Andreas Schwab
2023-06-08 10:29 ` Richard Earnshaw (lists)
2023-06-08 10:33 ` Richard Earnshaw (lists)
2023-06-08 14:24 ` Richard Sandiford
2023-06-08 16:49 ` Mikael Morin
2023-06-13 15:26 ` Tamar Christina [this message]
2023-06-14 19:41 ` Richard Sandiford
2023-06-15 6:24 ` Richard Sandiford
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=VI1PR08MB532501BE8432A4B569870958FF55A@VI1PR08MB5325.eurprd08.prod.outlook.com \
--to=tamar.christina@arm.com \
--cc=Richard.Earnshaw@arm.com \
--cc=Richard.Sandiford@arm.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=morin-mikael@orange.fr \
--cc=nd@arm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).