genopinit: Split init_all_optabs [PR113575]
Checks
Commit Message
Hi,
init_all_optabs initializes > 10000 patterns for riscv targets. This
leads to pathological situations in dataflow analysis (which can occur
with many adjacent stores).
To alleviate this this patch makes genopinit split the init_all_optabs
function into several init_optabs_xx functions that each initialize 1000
patterns.
With this change insn-opinit.cc's compilation time is reduced from 4+
minutes to 1:30 and memory consumption decreases from 1.2G to 630M.
Bootstrapped and regtested on x86 and aarch64 (where we do split) and
on power10 (where we don't). Regtested on riscv.
Regards
Robin
gcc/ChangeLog:
PR other/113575
* genopinit.cc (main): Split init_all_optabs into functions
of 1000 patterns each.
---
gcc/genopinit.cc | 43 ++++++++++++++++++++++++++++++++++++++-----
1 file changed, 38 insertions(+), 5 deletions(-)
Comments
On Fri, Jan 26, 2024 at 9:17 AM Robin Dapp <rdapp.gcc@gmail.com> wrote:
>
> Hi,
>
> init_all_optabs initializes > 10000 patterns for riscv targets. This
> leads to pathological situations in dataflow analysis (which can occur
> with many adjacent stores).
> To alleviate this this patch makes genopinit split the init_all_optabs
> function into several init_optabs_xx functions that each initialize 1000
> patterns.
>
> With this change insn-opinit.cc's compilation time is reduced from 4+
> minutes to 1:30 and memory consumption decreases from 1.2G to 630M.
>
> Bootstrapped and regtested on x86 and aarch64 (where we do split) and
> on power10 (where we don't). Regtested on riscv.
OK.
Thanks,
Richard.
> Regards
> Robin
>
> gcc/ChangeLog:
>
> PR other/113575
>
> * genopinit.cc (main): Split init_all_optabs into functions
> of 1000 patterns each.
> ---
> gcc/genopinit.cc | 43 ++++++++++++++++++++++++++++++++++++++-----
> 1 file changed, 38 insertions(+), 5 deletions(-)
>
> diff --git a/gcc/genopinit.cc b/gcc/genopinit.cc
> index 88ccafa5b2c..d8682b2a9ad 100644
> --- a/gcc/genopinit.cc
> +++ b/gcc/genopinit.cc
> @@ -367,11 +367,44 @@ main (int argc, const char **argv)
> fprintf (s_file, " { %#08x, CODE_FOR_%s },\n", p->sort_num, p->name);
> fprintf (s_file, "};\n\n");
>
> - 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");
> + /* 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");
> + }
> + 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");
> + }
>
> fprintf (s_file,
> "/* Returns TRUE if the target supports any of the partial vector\n"
> --
> 2.43.0
@@ -367,11 +367,44 @@ main (int argc, const char **argv)
fprintf (s_file, " { %#08x, CODE_FOR_%s },\n", p->sort_num, p->name);
fprintf (s_file, "};\n\n");
- 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");
+ /* 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");
+ }
+ 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");
+ }
fprintf (s_file,
"/* Returns TRUE if the target supports any of the partial vector\n"