When md_reader is reading insn attributes from md files, it accepts
expressions like (symbol_ref { code }) and (symbol_ref "{ code }")
as valid expressions. However, when generating insn-attrtab.cc, it
would print the {} block as an expression, which is not valid C++ syntax.
The conclusion is that to date, no backend is using that syntax, and
hence we can assign a new semantic to such {} blocks:
| The value of a (symbol_ref { code }) expression is the value returned
| by the {} code block (when taken as the body of a C++ function).
No changes to the md scanner are required; all what's needed is to print
the code from {} blocks in such a way that it works as the body of a C++
function / lambda expression. To that end, md_reader::fprint_c_condition()
now issues code as follows to insn-attrtab.cc:
return [&]() -> attr_desc.cxx_type { code } ();
where the capture provides code access to local variables like "insn".
Without this patch, the issued code was basically return { code };
The patch bootstraps + regtests with no changes.
Ok for trunk?
Johann
p.s. Some months ago I discussed the feature with Richard, and he said
that the printer should make no attempts whatsoever to detect invalid
syntax (like for example a block without return statement), and all
diagnosis should be performed by the compiler when insn-attrtab.cc is
being compiled.
--
md_reader: Support (symbol_ref { code }) in insn attributes.
When md_reader is reading insn attributes from md files, it accepts
expressions like (symbol_ref { code }) and (symbol_ref "{ code }")
as valid expressions. However, when generating insn-attrtab.cc, it
would print the {} block as an expression, which is not valid C++ syntax.
The conclusion is that to date, no backend is using that syntax, and
hence we can assign a new semantic to such {} blocks:
| The value of a (symbol_ref { code }) expression is the value returned
| by the {} code block (when taken as the body of a C++ function).
No changes to the md scanner are required; all what's needed is to print
the code from {} blocks in such a way that it works as the body of a C++
function / lambda expression. To that end, md_reader::fprint_c_condition()
now issues code as follows to insn-attrtab.cc:
return [&]() -> attr_desc.cxx_type { code } ();
where the capture provides code access to local variables like "insn".
Without this patch, the issued code was basically return { code };
gcc/
* doc/md.texi (Attribute Expressions) <symbol_ref>: Document it.
* genattrtab.cc (write_attr_value) [SYMBOL_REF]: Pass down
attr->cxx_type to rtx_reader_ptr->fprint_c_condition().
(write_test_expr) [MATCH_TEST]: Pass down "bool" as cxx_type
to rtx_reader_ptr->fprint_c_condition().
* genconditions.cc (write_one_condition): Same.
* genrecog.cc (print_test) [rtx_test::C_TEST]: Same.
* read-md.cc (md_reader::fprint_c_condition): Add cxx_type
argument and pass it down to recursive invocations.
When cond starts with a '{', then use cond as the body of a C++
lambda expression that's evaluated in place.
(md_reader::print_c_condition): Add cxx_type argument.
* read-md.h (md_reader::fprint_c_condition)
(md_reader::print_c_condition): Add cxx_type argument.
md_reader: Support (symbol_ref { code }) in insn attributes.
When md_reader is reading insn attributes from md files, it accepts
expressions like (symbol_ref { code }) and (symbol_ref "{ code }")
as valid expressions. However, when generating insn-attrtab.cc, it
would print the {} block as an expression, which is not valid C++ syntax.
The conclusion is that to date, no backend is using that syntax, and
hence we can assign a new semantic to such {} blocks:
| The value of a (symbol_ref { code }) expression is the value returned
| by the {} code block (when taken as the body of a C++ function).
No changes to the md scanner are required; all what's needed is to print
the code from {} blocks in such a way that it works as the body of a C++
function / lambda expression. To that end, md_reader::fprint_c_condition()
now issues code as follows to insn-attrtab.cc:
return [&]() -> attr_desc.cxx_type { code } ();
where the capture provides code access to local variables like "insn".
Without this patch, the issued code was basically return { code };
gcc/
* doc/md.texi (Attribute Expressions) <symbol_ref>: Document it.
* genattrtab.cc (write_attr_value) [SYMBOL_REF]: Pass down
attr->cxx_type to rtx_reader_ptr->fprint_c_condition().
(write_test_expr) [MATCH_TEST]: Pass down "bool" as cxx_type
to rtx_reader_ptr->fprint_c_condition().
* genconditions.cc (write_one_condition): Same.
* genrecog.cc (print_test) [rtx_test::C_TEST]: Same.
* read-md.cc (md_reader::fprint_c_condition): Add cxx_type
argument and pass it down to recursive invocations.
When cond starts with a '{', then use cond as the body of a C++
lambda expression that's evaluated in place.
(md_reader::print_c_condition): Add cxx_type argument.
* read-md.h (md_reader::fprint_c_condition)
(md_reader::print_c_condition): Add cxx_type argument.
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index a9259112251..4d18385a1d5 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -10277,6 +10277,57 @@ so there is no need to explicitly convert the expression into a boolean
(match_test "(x & 2) != 0")
@end smallexample
+@cindex @code{symbol_ref} and attributes
+@item (symbol_ref "@var{quoted-c-expr}")
+
+Specifies the value of the attribute sub-expression as a C++ expression,
+where the surrounding quotes are not part of the expression.
+Similar to @code{match_test}, variables @var{insn}, @var{operands[]}
+and @var{which_alternative} are available. Moreover, code and mode
+attributes can be used to compose the resulting C++ expression.
+Here is an example for the case where the according insn
+has exactly one mode iterator:
+
+@smallexample
+(set (attr "length")
+ (symbol_ref "1 + GET_MODE_SIZE (<MODE>mode)"))
+@end smallexample
+
+See @ref{Mode Iterators} and @ref{Code Iterators}.
+
+@item (symbol_ref "@{ @var{quoted-c-code} @}")
+@itemx (symbol_ref @{ @var{c-code} @})
+
+The value of this subexpression is determined by running the specfied block
+of C++ code which returns the desired value. The braces are part of the
+code, whereas the quotes in the quoted form are not.
+
+This variant of @code{symbol_ref} allows for more complex code than
+just a single C++ expression, like for example:
+
+@smallexample
+(set (attr "length")
+ (symbol_ref
+ @{
+ int len;
+ some_function (insn, <CODE>, <MODE>mode, & len);
+ return len;
+ @}))
+@end smallexample
+
+for an insn that has one code iterator and one mode iterator.
+Again, variables @var{insn}, @var{operands[]} and @var{which_alternative}
+can be used. The unquoted form only supports a subset of C++,
+for example no C comments are supported, and strings that contain
+characters like @samp{@}} are problematic and may need to be escaped
+as @samp{\@}}.
+
+The return type is @code{int} for the @var{length} attribute, and
+@code{enum attr_@var{name}} for an insn attribute named @var{name}.
+The types and available enum values can be looked up in
+@file{$builddir/gcc/insn-attr-common.h}.
+
+
@cindex @code{le} and attributes
@cindex @code{leu} and attributes
@cindex @code{lt} and attributes
diff --git a/gcc/genattrtab.cc b/gcc/genattrtab.cc
index 2a51549ddd4..63ddef84469 100644
--- a/gcc/genattrtab.cc
+++ b/gcc/genattrtab.cc
@@ -3707,7 +3707,7 @@ write_test_expr (FILE *outf, rtx exp, unsigned int attrs_cached, int flags,
break;
case MATCH_TEST:
- rtx_reader_ptr->fprint_c_condition (outf, XSTR (exp, 0));
+ rtx_reader_ptr->fprint_c_condition (outf, XSTR (exp, 0), "bool");
if (flags & FLG_BITWISE)
fprintf (outf, " != 0");
break;
@@ -4385,7 +4385,8 @@ write_attr_value (FILE *outf, class attr_desc *attr, rtx value)
break;
case SYMBOL_REF:
- rtx_reader_ptr->fprint_c_condition (outf, XSTR (value, 0));
+ rtx_reader_ptr->fprint_c_condition (outf, XSTR (value, 0),
+ attr->cxx_type);
break;
case ATTR:
diff --git a/gcc/genconditions.cc b/gcc/genconditions.cc
index 13963dc3ff4..8a55f0f1033 100644
--- a/gcc/genconditions.cc
+++ b/gcc/genconditions.cc
@@ -141,9 +141,9 @@ write_one_condition (void **slot, void * ARG_UNUSED (dummy))
}
fputs ("\",\n __builtin_constant_p ", stdout);
- rtx_reader_ptr->print_c_condition (test->expr);
+ rtx_reader_ptr->print_c_condition (test->expr, "$bool");
fputs ("\n ? (int) ", stdout);
- rtx_reader_ptr->print_c_condition (test->expr);
+ rtx_reader_ptr->print_c_condition (test->expr, "$bool");
fputs ("\n : -1 },\n", stdout);
return 1;
}
diff --git a/gcc/genrecog.cc b/gcc/genrecog.cc
index ba09ec3b600..c597958a487 100644
--- a/gcc/genrecog.cc
+++ b/gcc/genrecog.cc
@@ -4762,7 +4762,7 @@ print_test (output_state *os, const rtx_test &test, bool is_param,
gcc_assert (!is_param && value == 1);
if (invert_p)
printf ("!");
- rtx_reader_ptr->print_c_condition (test.u.string);
+ rtx_reader_ptr->print_c_condition (test.u.string, "bool");
break;
case rtx_test::ACCEPT:
diff --git a/gcc/read-md.cc b/gcc/read-md.cc
index 93d1ea43781..2e04fffc45d 100644
--- a/gcc/read-md.cc
+++ b/gcc/read-md.cc
@@ -170,31 +170,54 @@ md_reader::join_c_conditions (const char *cond1, const char *cond2)
directive for COND if its original file position is known. */
void
-md_reader::fprint_c_condition (FILE *outf, const char *cond)
+md_reader::fprint_c_condition (FILE *outf, const char *cond,
+ const char *cxx_type)
{
const char **halves = (const char **) htab_find (m_joined_conditions, &cond);
if (halves != 0)
{
fprintf (outf, "(");
- fprint_c_condition (outf, halves[1]);
+ fprint_c_condition (outf, halves[1], cxx_type);
fprintf (outf, " && ");
- fprint_c_condition (outf, halves[2]);
+ fprint_c_condition (outf, halves[2], cxx_type);
fprintf (outf, ")");
}
else
{
fputc ('\n', outf);
fprint_md_ptr_loc (outf, cond);
- fprintf (outf, "(%s)", cond);
+ if (cond[0] == '{')
+ {
+ /* Resulting C++ code is like "( [&]() -> <cxx_type> <cond> () )"
+ where COND is actually the body of a function, including the
+ outer {}'s. Print this as a lambda that's evaluated in place.
+ The capture-all is required to have access to variables
+ like "insn". Objects like "operands[]" and "which_alternative"
+ are accessible since they are global or captured.
+ When the expression is not evaluated locally (not in a function),
+ then CXX_TYPE starts with a '$' to indicate that no capture
+ should be performed. */
+ bool no_capture = cxx_type && cxx_type[0] == '$';
+ if (cxx_type && no_capture)
+ fprintf (outf, "( []() -> %s %s () )", 1 + cxx_type, cond);
+ else if (cxx_type)
+ fprintf (outf, "( [&]() -> %s %s () )", cxx_type, cond);
+ else
+ fprintf (outf, "( [&]() /* unknown return type */ %s () )", cond);
+ }
+ else
+ {
+ fprintf (outf, "(%s)", cond);
+ }
}
}
/* Special fprint_c_condition for writing to STDOUT. */
void
-md_reader::print_c_condition (const char *cond)
+md_reader::print_c_condition (const char *cond, const char *cxx_type)
{
- fprint_c_condition (stdout, cond);
+ fprint_c_condition (stdout, cond, cxx_type);
}
/* A vfprintf-like function for reporting an error against line LINENO
diff --git a/gcc/read-md.h b/gcc/read-md.h
index 9703551a8fd..b6ee68647ec 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -204,8 +204,9 @@ class md_reader
void handle_enum (file_location loc, bool md_p);
const char *join_c_conditions (const char *cond1, const char *cond2);
- void fprint_c_condition (FILE *outf, const char *cond);
- void print_c_condition (const char *cond);
+ void fprint_c_condition (FILE *outf, const char *cond,
+ const char *cxx_type = nullptr);
+ void print_c_condition (const char *cond, const char *cxx_type = nullptr);
/* Defined in read-rtl.cc. */
const char *apply_iterator_to_string (const char *string);