From: Kyrylo Tkachov <[email protected]>
The decision tree that genrecog builds tests a pattern's .md condition on
every path that can accept that pattern, and the same condition guards
many patterns. So a condition is emitted once per decision that needs
it, in full, inline. On aarch64 that is 27344 emissions of 1059 distinct
conditions, and `(TARGET_SVE)' alone accounts for 5269 of them. Together
with the #line directive that read-md.cc puts in front of each one, they
are about a third of insn-recog-*.cc.
Give each condition a helper function in the header that every partition
already includes, and call it:
static inline bool
insn_condition_408 (rtx *operands ATTRIBUTE_UNUSED,
rtx_insn *insn ATTRIBUTE_UNUSED)
{
return
#line 1172 ".../config/aarch64/aarch64-sve2.md"
(TARGET_SVE2);
}
so that
if (rtx_equal_p (x5, operands[2])
&&
#line 1172 ".../config/aarch64/aarch64-sve2.md"
(TARGET_SVE2))
return 13383; /* *cond_urshlvnx4si_2 */
becomes
if (rtx_equal_p (x5, operands[2])
&& insn_condition_408 (operands, insn))
return 13383; /* *cond_urshlvnx4si_2 */
The helpers take the operands and the insn because that is everything a
condition may read, so no condition has to be classified and none is
treated specially. Nothing moves: each condition is still evaluated at
exactly the decision that evaluated it before, so the change cannot alter
what recog matches or in what order. The helpers are inline, so the host
compiler folds them back into their callers and the emitted code is the
same as before.
On aarch64, insn-recog-*.cc goes from 8994833 bytes in 292736 lines to
6362888 bytes in 228402 lines, and compiles in 50% less time,
with peak memory 387MB against 479MB. cc1 itself drops from 533MB to
512MB.
Compiling a 39-file C corpus with -mcpu=generic, cortex-a57, cortex-a53,
exynos-m1, tsv110, neoverse-v2 and neoverse-n1 gives identical
assembly over all 273 compilations, and the built compiler takes the same
time as before.
Bootstrapped on aarch64-none-linux-gnu.
Ok for trunk?
gcc/ChangeLog:
* genrecog.cc (md_conditions, md_condition_ids): New variables.
(md_condition_id, print_md_conditions): New functions.
(print_test): Call a helper for a C test rather than emitting the
condition.
(main): Write the helpers to the header.
Signed-off-by: Kyrylo Tkachov <[email protected]>
---
gcc/genrecog.cc | 57 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 56 insertions(+), 1 deletion(-)
diff --git a/gcc/genrecog.cc b/gcc/genrecog.cc
index 663620224ab..04fc2330018 100644
--- a/gcc/genrecog.cc
+++ b/gcc/genrecog.cc
@@ -113,6 +113,7 @@
#include "errors.h"
#include "read-md.h"
#include "gensupport.h"
+#include "hash-map.h"
#undef GENERATOR_FILE
enum true_rtx_doe {
@@ -1788,6 +1789,54 @@ public:
int peep2_count;
};
+/* The distinct .md conditions, in the order they were first printed, and a
+ map from the condition text to that position. A condition is written out
+ once as a helper function and called wherever it is needed, rather than
+ inlined at each of the decisions that test it. */
+
+static auto_vec<const char *> md_conditions;
+static hash_map<nofree_string_hash, unsigned int> md_condition_ids;
+
+/* Return the index of COND's helper function, registering it if this is the
+ first time it has been seen. */
+
+static unsigned int
+md_condition_id (const char *cond)
+{
+ bool existed;
+ unsigned int &id = md_condition_ids.get_or_insert (cond, &existed);
+ if (!existed)
+ {
+ id = md_conditions.length ();
+ md_conditions.safe_push (cond);
+ }
+ return id;
+}
+
+/* Write a helper function for each condition to F. They go in the header,
+ which every generated file includes after the target headers, so that a
+ condition is compiled once however many decisions test it.
+
+ The helpers take the operands and the insn, which is everything a
+ condition may read, and are declared inline so that the host compiler can
+ fold them back into their callers. */
+
+static void
+print_md_conditions (FILE *f)
+{
+ unsigned int i;
+ const char *cond;
+
+ FOR_EACH_VEC_ELT (md_conditions, i, cond)
+ {
+ fprintf (f, "\nstatic inline bool\ninsn_condition_%d "
+ "(rtx *operands ATTRIBUTE_UNUSED,\n"
+ "\t\t rtx_insn *insn ATTRIBUTE_UNUSED)\n{\n return ", i);
+ rtx_reader_ptr->print_c_condition (f, cond);
+ fprintf (f, ";\n}\n");
+ }
+}
+
/* Return true if TEST can safely be performed at D, where
the conditions in KC hold. TEST is known to occur along the
first path from D (i.e. always following the first transition
@@ -4762,10 +4811,13 @@ print_test (FILE *f, output_state *os, const rtx_test &test, bool is_param,
break;
case rtx_test::C_TEST:
+ /* Pattern routines take no insn, and pattern_c_test_p keeps C tests
+ out of them for that reason. */
gcc_assert (!is_param && value == 1);
if (invert_p)
fprintf (f, "!");
- rtx_reader_ptr->print_c_condition (f, test.u.string);
+ fprintf (f, "insn_condition_%d (operands, insn)",
+ md_condition_id (test.u.string));
break;
case rtx_test::ACCEPT:
@@ -5533,6 +5585,9 @@ main (int argc, const char **argv)
print_subroutine_group (output_files, header, &os, SPLIT, &split_root);
print_subroutine_group (output_files, header, &os, PEEPHOLE2, &peephole2_root);
+ /* Every test has been printed, so the set of conditions is complete. */
+ print_md_conditions (header);
+
fclose (header);
int ret = SUCCESS_EXIT_CODE;
--
2.50.1 (Apple Git-155)
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.