[PATCH 2/4] genopinit: Group optab patterns by condition
<[email protected]> Wed, 5 Aug 2026 16:35:24 +0200
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
From: Kyrylo Tkachov <[email protected]> insn-opinit.cc initializes one Boolean value for every optab pattern. Many assignments use the same target condition. The repeated assignments make the generated file expensive to optimize and produce a large initializer function. A measured AArch64 file has 3,412 patterns but only 128 exact conditions. A measured RISC-V file has 14,984 patterns but only 963 exact conditions. Record an index for each exact condition string while genopinit reads the machine description. Emit one representative HAVE_* value per condition and a compact pattern-to-condition map. Initialize pat_enable with one sequential loop. Use unsigned char or unsigned short when their ISO C minimum ranges hold all condition indices. Otherwise use unsigned int, which holds every GCC vec index on a supported host. For example, these four AArch64 HAVE_* macros all expand to TARGET_SVE. A shortened part of the old initializer is: ena[1021] = HAVE_while_ultsivnx16bi; /* TARGET_SVE */ ena[1022] = HAVE_while_ultdivnx16bi; /* TARGET_SVE */ ena[1023] = HAVE_while_ultsivnx8bi; /* TARGET_SVE */ ena[1024] = HAVE_while_ultdivnx8bi; /* TARGET_SVE */ The new initializer contains four one-byte condition indices and one representative TARGET_SVE expression: static const unsigned char pat_condition[NUM_OPTAB_PATTERNS] = { /* ... */ 9, 9, 9, 9, /* ... */ }; void init_all_optabs (struct target_optabs *optabs) { const bool condition_values[] = { /* ... */ !!HAVE_movvnx32bi, /* TARGET_SVE, condition 9 */ /* ... */ }; for (unsigned int i = 0; i < NUM_OPTAB_PATTERNS; ++i) optabs->pat_enable[i] = condition_values[pat_condition[i]]; } The initializer therefore contains one TARGET_SVE expression for these four patterns instead of four copies. The same reduction applies to every shared condition. The condition values remain local to init_all_optabs, so each call evaluates them for the current target options. Each pat_enable entry also remains independent for swap_optab_enable. On AArch64, direct compilation of insn-opinit.cc takes about 94% less wall time and 64% less peak memory. On x86_64, it takes about 34% less wall time and 19% less peak memory. The AArch64 initializer text is about 95% smaller. The x86_64 initializer text is about 77% smaller. Bootstrapped and tested on aarch64-none-linux-gnu and x86_64-linux. Ok for trunk? Thanks, Kyrill gcc/ChangeLog: * genopinit.cc (pattern_info): New. (patterns): Use pattern_info. (condition_map, condition_representatives): New. (gen_insn): Record the condition index for each pattern. (pattern_cmp): Use pattern_info. (main): Emit one value per condition, a compact condition map, and one initialization loop. Suggested-by: Tamar Christina <[email protected]> Signed-off-by: Kyrylo Tkachov <[email protected]> --- gcc/genopinit.cc | 98 +++++++++++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 43 deletions(-) diff --git a/gcc/genopinit.cc b/gcc/genopinit.cc index 62eaf5bd378..77aaa6a858e 100644 --- a/gcc/genopinit.cc +++ b/gcc/genopinit.cc @@ -35,22 +35,45 @@ static const char * const rtx_upname[] = { #undef DEF_RTL_EXPR +struct pattern_info : optab_pattern +{ + unsigned int condition_index; +}; + /* Vector in which to collect insns that match. */ -static vec<optab_pattern> patterns; +static vec<pattern_info> patterns; + +/* Maps each condition to its index in CONDITION_REPRESENTATIVES. */ +static hash_map<nofree_string_hash, unsigned int> condition_map; + +/* One representative optab pattern name for each unique condition. */ +static vec<const char *> condition_representatives; static void gen_insn (md_rtx_info *info) { - optab_pattern p; + pattern_info p; if (find_optab (&p, XSTR (info->def, 0))) - patterns.safe_push (p); + { + const char *condition = get_c_test (info->def); + bool existed; + unsigned int &condition_index + = condition_map.get_or_insert (condition, &existed); + if (!existed) + { + condition_index = condition_representatives.length (); + condition_representatives.safe_push (p.name); + } + p.condition_index = condition_index; + patterns.safe_push (p); + } } static int pattern_cmp (const void *va, const void *vb) { - const optab_pattern *a = (const optab_pattern *)va; - const optab_pattern *b = (const optab_pattern *)vb; + const pattern_info *a = (const pattern_info *)va; + const pattern_info *b = (const pattern_info *)vb; return a->sort_num - b->sort_num; } @@ -178,7 +201,7 @@ main (int argc, const char **argv) { FILE *h_file, *s_file; unsigned int i, j, n, last_kind[5]; - optab_pattern *p; + pattern_info *p; progname = "genopinit"; @@ -367,44 +390,33 @@ main (int argc, const char **argv) fprintf (s_file, " { %#08x, CODE_FOR_%s },\n", p->sort_num, p->name); fprintf (s_file, "};\n\n"); - /* Some targets like riscv have a large number of patterns. In order to - prevent pathological situations in dataflow analysis split the init - function into separate ones that initialize 1000 patterns each. */ - - const int patterns_per_function = 1000; - - if (patterns.length () > patterns_per_function) - { - unsigned num_init_functions - = patterns.length () / patterns_per_function + 1; - for (i = 0; i < num_init_functions; i++) - { - fprintf (s_file, "static void\ninit_optabs_%02d " - "(struct target_optabs *optabs)\n{\n", i); - fprintf (s_file, " bool *ena = optabs->pat_enable;\n"); - unsigned start = i * patterns_per_function; - unsigned end = MIN (patterns.length (), - (i + 1) * patterns_per_function); - for (j = start; j < end; ++j) - fprintf (s_file, " ena[%u] = HAVE_%s;\n", j, patterns[j].name); - fprintf (s_file, "}\n\n"); - } - - fprintf (s_file, "void\ninit_all_optabs " - "(struct target_optabs *optabs)\n{\n"); - for (i = 0; i < num_init_functions; ++i) - fprintf (s_file, " init_optabs_%02d (optabs);\n", i); - fprintf (s_file, "}\n\n"); - } + /* Base the first two limits on the minimum ranges required by ISO C. The + host that compiles the generated file can differ from the machine that + runs this generator. GCC hosts have at least 32-bit int, while vec has + a 31-bit capacity, so unsigned int holds all remaining indices. */ + const char *condition_index_type; + if (condition_representatives.length () <= 256) + condition_index_type = "unsigned char"; + else if (condition_representatives.length () <= 65536) + condition_index_type = "unsigned short"; else - { - fprintf (s_file, "void\ninit_all_optabs " - "(struct target_optabs *optabs)\n{\n"); - fprintf (s_file, " bool *ena = optabs->pat_enable;\n"); - for (i = 0; patterns.iterate (i, &p); ++i) - fprintf (s_file, " ena[%u] = HAVE_%s;\n", i, p->name); - fprintf (s_file, "}\n\n"); - } + condition_index_type = "unsigned int"; + fprintf (s_file, "static const %s " + "pat_condition[NUM_OPTAB_PATTERNS] = {\n", condition_index_type); + for (i = 0; patterns.iterate (i, &p); ++i) + fprintf (s_file, " %u,\n", p->condition_index); + fprintf (s_file, "};\n\n"); + + fprintf (s_file, "void\ninit_all_optabs " + "(struct target_optabs *optabs)\n{\n" + " const bool condition_values[] = {\n"); + for (i = 0; i < condition_representatives.length (); ++i) + fprintf (s_file, " !!HAVE_%s,\n", condition_representatives[i]); + fprintf (s_file, + " };\n" + " for (unsigned int i = 0; i < NUM_OPTAB_PATTERNS; ++i)\n" + " optabs->pat_enable[i] = condition_values[pat_condition[i]];\n" + "}\n\n"); fprintf (s_file, "/* Returns TRUE if the target supports any of the partial vector\n" -- 2.50.1 (Apple Git-155)