From: "Martin Liška" <mliska@suse.cz>
To: Richard Biener <rguenther@suse.de>
Cc: gcc-patches@gcc.gnu.org
Subject: Re: [RFH] split {generic,gimple}-match.c files
Date: Tue, 04 Sep 2018 15:07:00 -0000 [thread overview]
Message-ID: <c9c0ee2c-79dc-8374-b55b-655fd2e161c6@suse.cz> (raw)
In-Reply-To: <alpine.LSU.2.20.1809031640350.16707@zhemvz.fhfr.qr>
[-- Attachment #1: Type: text/plain, Size: 8488 bytes --]
On 09/03/2018 04:43 PM, Richard Biener wrote:
> On Mon, 3 Sep 2018, Martin Liška wrote:
>
>> On 09/03/2018 04:00 PM, Richard Biener wrote:
>>> On Mon, 3 Sep 2018, Martin Liška wrote:
>>>
>>>> On 09/03/2018 02:54 PM, Martin Liška wrote:
>>>>> On 09/03/2018 02:41 PM, Richard Biener wrote:
>>>>>> On Mon, 3 Sep 2018, Martin Liška wrote:
>>>>>>
>>>>>>> On 04/25/2018 01:42 PM, Richard Biener wrote:
>>>>>>>>
>>>>>>>> The following patch^Whack splits $subject files into three, one
>>>>>>>> for the predicates (due to an implementation detail) and two for
>>>>>>>> the rest - for now into similar LOC size files.
>>>>>>>>
>>>>>>>> I'd like to get help on the makefile changes to make them less
>>>>>>>> verbose, somehow globbing the -[12p] parts.
>>>>>>>>
>>>>>>>> Also you can see the split point is manually chosen which means
>>>>>>>> it will bitrot. Timings for the stage2 compiles on a x86_64
>>>>>>>> box are
>>>>>>>>
>>>>>>>> gimple-match-p.c 5s
>>>>>>>> generic-match-p.c 3s
>>>>>>>> gimple-match-1.c 85s
>>>>>>>> generic-match-1.c 56s
>>>>>>>> gimple-match-2.c 82s
>>>>>>>> generic-match-2.c 31s
>>>>>>>>
>>>>>>>> the required header files are quite big (and of course everything
>>>>>>>> needs to be exported without the analysis work becoming too cumbersome),
>>>>>>>> it's 3342 LOC for gimple-match-head.h and 1556 LOC for
>>>>>>>> generic-match-head.h
>>>>>>>>
>>>>>>>> The machine I tested is quite fast so the 80ish second timings are still
>>>>>>>> too slow I guess and thus splitting up into four files for gimple and
>>>>>>>> three files for generic looks better.
>>>>>>>>
>>>>>>>> Note we lose some inlining/cloning capability in the splitting process
>>>>>>>> (I see quite a bit of constprop/isra work being done on the generated
>>>>>>>> files). I didn't try to measure the runtime impact though.
>>>>>>>>
>>>>>>>> The patch still needs quite some TLC, it really is a bit hacky but I'd
>>>>>>>> like to get feedback on the approach and I didn't want to spend time
>>>>>>>> on programatically finding optimal split points (so everything is output
>>>>>>>> in the same semi-random order as before).
>>>>>>>>
>>>>>>>> Richard.
> ...
>>>>>>> I took a look at gimple-match.c and what about doing a split in following way:
>>>>>>> - all gimple_simplify_$number going into a separate header file (~12000 LOC)
>>>>>>> - all the function can be marked as static inline
>>>>>>> - all other gimple_simplify_$code can be split into arbitrary number of parts
>>>>>>> - we have 287 such functions where each function only calls gimple_simplify_$number and
>>>>>>> on average there 10 of such calls
>>>>>>> - that would allow to remove most of gimple_simplify_$number functions from the header file
>>>>>>>
>>>>>>> Richi do you think it will be viable?
>>>>>>
>>>>>> That relies on the cgraph code DCEing all unused gimple_simplify_$number
>>>>>> functions from the header fast as they are now effectively duplicated
>>>>>> into all parts, correct? Also I'm not sure if we actually want to inline
>>>>>> them... they are split out to get both code size and compile-time
>>>>>> under control. Unfortunately we have still high max-inline-insns-single
>>>>>> which is used for inline marked functions.
>>>>>>
>>>>>> Eventually doing a "proper" partitioning algorithm is viable, that is,
>>>>>> partition based on gimple_simplify_$code and put gimple_simplify_$number
>>>>>> where they are used. If they are used across different codes then
>>>>>> merge those partitions. I guess you'll see that that'll merge the
>>>>>> biggest _$code parititions :/ (MINUS_EXPR, PLUS_EXPR).
>>>>>
>>>>> Yes, that should be much better. I'm attaching a 'callgraph' that was done by grepping.
>>>>> Function starting at the beginning of a line is function definition, with an indentation
>>>>> one can see calls.
>>>>>
>>>>> Yes, PLUS and MINUS call ~20 gimple_simplify_$number calls.
>>>>>
>>>>> Well, generating some simple call graph format for the source file and a source file
>>>>> annotation of nodes can be input for a partitioning tool that can do the split.
>>>>>
>>>>> Issue with the generated files is that one needs to fix the most offenders (*-match.c, insn-recog.c, insn-emit.c, ..)
>>>>> in order to see some improvement.
>>>>>
>>>>> Looking at insn-recog.c, maybe similar callgraph-based split can be done for recog_$number functions?
>>>>>
>>>>> Martin
>>>>>
>>>>>>
>>>>>> Richard.
>>>>>>
>>>>>
>>>>
>>>> I'm sending SCC components for gimple-match.c. So there are 3 quite big one and rest is small. It's questionable
>>>> whether partitioning based on that will provide desired speed up?
>>>
>>> When I experimented split based on # of functions wasn't working well,
>>> only split based on # of lines did. I'd still expect that eventually
>>> basing the split on the SCC components makes sense if you use say,
>>> the biggest 4 (but measure size in # lines) and merge the rest evenly.
>>
>> I see! Note that shrinking gimple-match.o 4 times will be probably sufficient for general
>> speed up:
>> https://gcc.gnu.org/bugzilla/attachment.cgi?id=43440
>>
>>>
>>> It would be nice if that all would be scriptable instead of coding it
>>> into genmatch.c but that's of course possible as well - just add
>>> some extra "passes" over code-gen as I did in the hac^Wpatch. You
>>
>> That would be my plan, genmatch can mark in C comments function that can be partitioned
>> and callgraph of these functions.
>>
>>> could use graphds.c routines to compute SCCs for example. Knowing
>>> # lines beforehand is a bit hard though - code-generating into
>>> a set of character buffers might be possible but I wired everything
>>> to use FILE ... (and no stringstreams in the C library).
>>> And no, please do not convert to C++ streams ;))
>>
>> ... and a C++ splitter can do the rest: read content, do SCC, split to N parts
>> and stream out.
>>
>> I can work on that. Questionable is still Makefile integration of such
>> parallelism?
>
> Well, just hard-code the number of pieces and thus the pices to
> compile in the end...
>
> Of course we shouldn't add any additional build dependencies
> (a "C++ splitter"). Adding additional annotation to the genmatch
> generated sources may be OK but then eventually doing everything in
> genmatch isn't too complicated (putting aside that # of lines metric...).
>
> Richard.
>
Hi.
There's working solution for {gimple,generic}-match.c. It introduces splitter.cc which
parses annotated generated files and split it according to call graph provided by annotations.
Currently I copied a SCC implementation as graphds.c has quite some dependencies (xrealloc, bitmap,..).
Questionable how to reduce the dependencies?
For gimple-match.c the biggest SCC component contains about 1/4 LOC, which means maximal reasonable number
of parts is equal to 4. Doing that the biggest component is compiled with -O2 14.5s, which the original gimple-match.c
50.0s. That sounds promising:
l gimple-match-part*.c
-rw-r--r-- 1 marxin users 791442 Sep 4 17:02 gimple-match-part-0.c
-rw-r--r-- 1 marxin users 748610 Sep 4 17:02 gimple-match-part-1.c
-rw-r--r-- 1 marxin users 783749 Sep 4 17:02 gimple-match-part-2.c
-rw-r--r-- 1 marxin users 828990 Sep 4 17:02 gimple-match-part-3.c
-rw-r--r-- 1 marxin users 103130 Sep 4 17:02 gimple-match-part-footer.c
for generic-match.c:
l generic-match-part*.c
-rw-r--r-- 1 marxin users 528712 Sep 4 17:02 generic-match-part-0.c
-rw-r--r-- 1 marxin users 517120 Sep 4 17:02 generic-match-part-1.c
-rw-r--r-- 1 marxin users 519777 Sep 4 17:02 generic-match-part-2.c
-rw-r--r-- 1 marxin users 221971 Sep 4 17:02 generic-match-part-3.c
-rw-r--r-- 1 marxin users 14596 Sep 4 17:02 generic-match-part-footer.c
There are some issues with functions that live in gimple-match-head.c, these
should live in a header file the parts can include. I also renamed
gimple_simplify function that live in gimple-match.c to gimple_simplify_generated
as they clash with these that are in gimple-match-head.c.
There are still various questions:
- how to make the split process optional, how to modify then Makefile?
- SCC implementation should be shared with graphds.c
- splitter.cc should be cleaned up
- in order to achieve real speed up we need to split also other generated (and also dwarf2out.c, i386.c, ..) files:
here I'm most concerned about insn-recog.c, which can't be split the same way without ending up with a single huge SCC component.
Ideas what to do with that file?
Thoughts?
Martin
[-- Attachment #2: 0001-Come-up-with-splitter-for-gimple-and-generic-match-f.patch --]
[-- Type: text/x-patch, Size: 37255 bytes --]
From 0f57bea9576867140846abb8703dba878eb20c70 Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Tue, 4 Sep 2018 14:54:17 +0200
Subject: [PATCH] Come up with splitter for gimple and generic match files.
---
gcc/Makefile.in | 49 ++++-
gcc/genmatch.c | 57 ++++--
gcc/gimple-match-head-common.h | 191 ++++++++++++++++++
gcc/gimple-match-head.c | 211 +++----------------
gcc/splitter.cc | 357 +++++++++++++++++++++++++++++++++
5 files changed, 647 insertions(+), 218 deletions(-)
create mode 100644 gcc/gimple-match-head-common.h
create mode 100644 gcc/splitter.cc
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index e008f63b2ea..3cae9bcfd8d 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -218,8 +218,16 @@ gengtype-lex.o-warn = -Wno-error
libgcov-util.o-warn = -Wno-error
libgcov-driver-tool.o-warn = -Wno-error
libgcov-merge-tool.o-warn = -Wno-error
-gimple-match.o-warn = -Wno-unused
-generic-match.o-warn = -Wno-unused
+gimple-match-part-0.o-warn = -Wno-unused
+gimple-match-part-1.o-warn = -Wno-unused
+gimple-match-part-2.o-warn = -Wno-unused
+gimple-match-part-3.o-warn = -Wno-unused
+gimple-match-part-footer.o-warn = -Wno-unused
+generic-match-part-0.o-warn = -Wno-unused
+generic-match-part-1.o-warn = -Wno-unused
+generic-match-part-2.o-warn = -Wno-unused
+generic-match-part-3.o-warn = -Wno-unused
+generic-match-part-footer.o-warn = -Wno-unused
dfp.o-warn = -Wno-strict-aliasing
# All warnings have to be shut off in stage1 if the compiler used then
@@ -522,7 +530,7 @@ CROSS_SYSTEM_HEADER_DIR = @CROSS_SYSTEM_HEADER_DIR@
# to directories that might not exist yet.
# The sed idiom for this is to repeat the search-and-replace until it doesn't match, using :a ... ta.
# Use single quotes here to avoid nested double- and backquotes, this
-# macro is also used in a double-quoted context.
+# macro is also used inmem_alloc_description a double-quoted context.
SYSTEM_HEADER_DIR = `echo @SYSTEM_HEADER_DIR@ | sed -e :a -e 's,[^/]*/\.\.\/,,' -e ta`
# Path to the system headers on the build machine.
@@ -1209,8 +1217,17 @@ C_COMMON_OBJS = c-family/c-common.o c-family/c-cppbuiltin.o c-family/c-dump.o \
# will build them sooner, because they are large and otherwise tend to be
# the last objects to finish building.
OBJS = \
- gimple-match.o \
- generic-match.o \
+ gimple-match-part-0.o \
+ gimple-match-part-1.o \
+ gimple-match-part-2.o \
+ gimple-match-part-3.o \
+ gimple-match-part-footer.o \
+ gimple-match-head.o \
+ generic-match-part-0.o \
+ generic-match-part-1.o \
+ generic-match-part-2.o \
+ generic-match-part-3.o \
+ generic-match-part-footer.o \
insn-attrtab.o \
insn-automata.o \
insn-dfatab.o \
@@ -2507,10 +2524,19 @@ s-tm-texi: build/genhooks$(build_exeext) $(srcdir)/doc/tm.texi.in
false; \
fi
-gimple-match.c: s-match gimple-match-head.c ; @true
-generic-match.c: s-match generic-match-head.c ; @true
+gimple-match-part-0.c: s-match gimple-match-head.c ; @true
+gimple-match-part-1.c: s-match gimple-match-head.c ; @true
+gimple-match-part-2.c: s-match gimple-match-head.c ; @true
+gimple-match-part-3.c: s-match gimple-match-head.c ; @true
+gimple-match-part-footer.c: s-match gimple-match-head.c ; @true
-s-match: build/genmatch$(build_exeext) $(srcdir)/match.pd cfn-operators.pd
+generic-match-part-0.c: s-match generic-match-head.c ; @true
+generic-match-part-1.c: s-match generic-match-head.c ; @true
+generic-match-part-2.c: s-match generic-match-head.c ; @true
+generic-match-part-3.c: s-match generic-match-head.c ; @true
+generic-match-part-footer.c: s-match generic-match-head.c ; @true
+
+s-match: build/genmatch$(build_exeext) $(srcdir)/match.pd cfn-operators.pd build/splitter$(build_exeext)
$(RUN_GEN) build/genmatch$(build_exeext) --gimple $(srcdir)/match.pd \
> tmp-gimple-match.c
$(RUN_GEN) build/genmatch$(build_exeext) --generic $(srcdir)/match.pd \
@@ -2519,6 +2545,8 @@ s-match: build/genmatch$(build_exeext) $(srcdir)/match.pd cfn-operators.pd
gimple-match.c
$(SHELL) $(srcdir)/../move-if-change tmp-generic-match.c \
generic-match.c
+ build/splitter$(build_exeext) generic
+ build/splitter$(build_exeext) gimple
$(STAMP) s-match
GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
@@ -2793,6 +2821,7 @@ build/genmatch.o : genmatch.c $(BCONFIG_H) $(SYSTEM_H) \
build/gencfn-macros.o : gencfn-macros.c $(BCONFIG_H) $(SYSTEM_H) \
$(CORETYPES_H) errors.h $(HASH_TABLE_H) hash-set.h builtins.def \
internal-fn.def
+build/splitter.o: splitter.cc
# Compile the programs that generate insn-* from the machine description.
# They are compiled with $(COMPILER_FOR_BUILD), and associated libraries,
@@ -2836,6 +2865,10 @@ endif
build/genmatch$(build_exeext) : $(BUILD_CPPLIB) \
$(BUILD_ERRORS) build/vec.o build/hash-table.o build/sort.o
+build/splitter$(build_exeext) : $(BUILD_CPPLIB) \
+ $(BUILD_ERRORS) splitter.o
+ g++ -o $@ $^
+
# These programs are not linked with the MD reader.
build/gengtype$(build_exeext) : build/gengtype-lex.o build/gengtype-parse.o \
build/gengtype-state.o build/version.o build/errors.o
diff --git a/gcc/genmatch.c b/gcc/genmatch.c
index 5f1691ae206..3a06210d0c2 100644
--- a/gcc/genmatch.c
+++ b/gcc/genmatch.c
@@ -3551,6 +3551,7 @@ dt_simplify::gen (FILE *f, int indent, bool gimple)
/* If we have a split-out function for the actual transform, call it. */
if (info && info->fname)
{
+ fprintf (f, "// call-fn:%s\n", info->fname);
if (gimple)
{
fprintf_indent (f, indent, "if (%s (res_op, seq, "
@@ -3682,6 +3683,27 @@ sinfo_hashmap_traits::equal_keys (const key_type &v,
return compare_op (v->s->result, v->s, candidate->s->result, candidate->s);
}
+static void
+print_simplify_fnheader (FILE *f, bool gimple, const char *op, unsigned n, bool declaration)
+{
+ if (gimple)
+ fprintf (f, "%sbool\n"
+ "gimple_simplify_%s (gimple_match_op *res_op,"
+ " gimple_seq *seq,\n"
+ " tree (*valueize)(tree) "
+ "ATTRIBUTE_UNUSED,\n"
+ " code_helper ARG_UNUSED (code), tree "
+ "ARG_UNUSED (type)", declaration ? "extern " : "",
+ op);
+ else
+ fprintf (f, "extern tree\n"
+ "generic_simplify_%s (location_t ARG_UNUSED (loc), enum "
+ "tree_code ARG_UNUSED (code), const tree ARG_UNUSED (type)",
+ op);
+ for (unsigned i = 0; i < n; ++i)
+ fprintf (f, ", tree op%d", i);
+ fprintf (f, ")%s\n", declaration ? ";" : "");
+}
/* Main entry to generate code for matching GIMPLE IL off the decision
tree. */
@@ -3719,8 +3741,10 @@ decision_tree::gen (FILE *f, bool gimple)
/* Generate a split out function with the leaf transform code. */
s->fname = xasprintf ("%s_simplify_%u", gimple ? "gimple" : "generic",
fcnt++);
+
+ fprintf (f, "\n// split-fn-begin:%s\n", s->fname);
if (gimple)
- fprintf (f, "\nstatic bool\n"
+ fprintf (f, "static bool\n"
"%s (gimple_match_op *res_op, gimple_seq *seq,\n"
" tree (*valueize)(tree) ATTRIBUTE_UNUSED,\n"
" const tree ARG_UNUSED (type), tree *ARG_UNUSED "
@@ -3755,6 +3779,7 @@ decision_tree::gen (FILE *f, bool gimple)
else
fprintf (f, " return NULL_TREE;\n");
fprintf (f, "}\n");
+ fprintf (f, "// split-fn-end\n");
}
fprintf (stderr, "removed %u duplicate tails\n", rcnt);
@@ -3774,23 +3799,10 @@ decision_tree::gen (FILE *f, bool gimple)
&& e->operation->kind != id_base::CODE))
continue;
- if (gimple)
- fprintf (f, "\nstatic bool\n"
- "gimple_simplify_%s (gimple_match_op *res_op,"
- " gimple_seq *seq,\n"
- " tree (*valueize)(tree) "
- "ATTRIBUTE_UNUSED,\n"
- " code_helper ARG_UNUSED (code), tree "
- "ARG_UNUSED (type)\n",
- e->operation->id);
- else
- fprintf (f, "\nstatic tree\n"
- "generic_simplify_%s (location_t ARG_UNUSED (loc), enum "
- "tree_code ARG_UNUSED (code), const tree ARG_UNUSED (type)",
- e->operation->id);
- for (unsigned i = 0; i < n; ++i)
- fprintf (f, ", tree op%d", i);
- fprintf (f, ")\n");
+ print_simplify_fnheader (f, gimple, e->operation->id, n, true);
+ fprintf (f, "\n// split-fn-begin:%s_%s\n", gimple ? "gimple" : "generic",
+ e->operation->id);
+ print_simplify_fnheader (f, gimple, e->operation->id, n, false);
fprintf (f, "{\n");
dop->gen_kids (f, 2, gimple);
if (gimple)
@@ -3798,13 +3810,14 @@ decision_tree::gen (FILE *f, bool gimple)
else
fprintf (f, " return NULL_TREE;\n");
fprintf (f, "}\n");
+ fprintf (f, "// split-fn-end\n");
}
/* Then generate the main entry with the outermost switch and
tail-calls to the split-out functions. */
if (gimple)
- fprintf (f, "\nstatic bool\n"
- "gimple_simplify (gimple_match_op *res_op, gimple_seq *seq,\n"
+ fprintf (f, "\nbool\n"
+ "gimple_simplify_generated (gimple_match_op *res_op, gimple_seq *seq,\n"
" tree (*valueize)(tree) ATTRIBUTE_UNUSED,\n"
" code_helper code, const tree type");
else
@@ -3868,7 +3881,7 @@ decision_tree::gen (FILE *f, bool gimple)
void
write_predicate (FILE *f, predicate_id *p, decision_tree &dt, bool gimple)
{
- fprintf (f, "\nbool\n"
+ fprintf (f, "\nstatic bool\n"
"%s%s (tree t%s%s)\n"
"{\n", gimple ? "gimple_" : "tree_", p->id,
p->nargs > 0 ? ", tree *res_ops" : "",
@@ -5117,7 +5130,7 @@ add_operator (VIEW_CONVERT2, "view_convert2", "tcc_unary", 1);
parser p (r);
if (gimple)
- write_header (stdout, "gimple-match-head.c");
+ write_header (stdout, "gimple-match-head-common.h");
else
write_header (stdout, "generic-match-head.c");
diff --git a/gcc/gimple-match-head-common.h b/gcc/gimple-match-head-common.h
new file mode 100644
index 00000000000..a854db32e7d
--- /dev/null
+++ b/gcc/gimple-match-head-common.h
@@ -0,0 +1,191 @@
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "target.h"
+#include "rtl.h"
+#include "tree.h"
+#include "gimple.h"
+#include "ssa.h"
+#include "cgraph.h"
+#include "fold-const.h"
+#include "fold-const-call.h"
+#include "stor-layout.h"
+#include "gimple-fold.h"
+#include "calls.h"
+#include "tree-dfa.h"
+#include "builtins.h"
+#include "gimple-match.h"
+#include "tree-pass.h"
+#include "internal-fn.h"
+#include "case-cfn-macros.h"
+#include "gimplify.h"
+#include "optabs-tree.h"
+#include "tree-eh.h"
+
+/* Return whether T is a constant that we'll dispatch to fold to
+ evaluate fully constant expressions. */
+
+static inline bool
+constant_for_folding (tree t)
+{
+ return (CONSTANT_CLASS_P (t)
+ /* The following is only interesting to string builtins. */
+ || (TREE_CODE (t) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (t, 0)) == STRING_CST));
+}
+
+/* Helper for gimple_simplify_generated valueizing OP using VALUEIZE and setting
+ VALUEIZED to true if valueization changed OP. */
+
+static inline tree
+do_valueize (tree op, tree (*valueize)(tree), bool &valueized)
+{
+ if (valueize && TREE_CODE (op) == SSA_NAME)
+ {
+ tree tem = valueize (op);
+ if (tem && tem != op)
+ {
+ op = tem;
+ valueized = true;
+ }
+ }
+ return op;
+}
+
+/* Routine to determine if the types T1 and T2 are effectively
+ the same for GIMPLE. If T1 or T2 is not a type, the test
+ applies to their TREE_TYPE. */
+
+static inline bool
+types_match (tree t1, tree t2)
+{
+ if (!TYPE_P (t1))
+ t1 = TREE_TYPE (t1);
+ if (!TYPE_P (t2))
+ t2 = TREE_TYPE (t2);
+
+ return types_compatible_p (t1, t2);
+}
+
+/* Return if T has a single use. For GIMPLE, we also allow any
+ non-SSA_NAME (ie constants) and zero uses to cope with uses
+ that aren't linked up yet. */
+
+static inline bool
+single_use (tree t)
+{
+ return TREE_CODE (t) != SSA_NAME || has_zero_uses (t) || has_single_use (t);
+}
+
+/* Return true if math operations should be canonicalized,
+ e.g. sqrt(sqrt(x)) -> pow(x, 0.25). */
+
+static inline bool
+canonicalize_math_p ()
+{
+ return !cfun || (cfun->curr_properties & PROP_gimple_opt_math) == 0;
+}
+
+/* Return true if math operations that are beneficial only after
+ vectorization should be canonicalized. */
+
+static inline bool
+canonicalize_math_after_vectorization_p ()
+{
+ return !cfun || (cfun->curr_properties & PROP_gimple_lvec) != 0;
+}
+
+/* Helper for the autogenerated code, get at the definition of NAME when
+ VALUEIZE allows that. */
+
+static inline gimple *
+get_def (tree (*valueize)(tree), tree name)
+{
+ if (valueize && ! valueize (name))
+ return NULL;
+ return SSA_NAME_DEF_STMT (name);
+}
+
+/* Helper for the autogenerated code, valueize OP. */
+
+static inline tree
+do_valueize (tree (*valueize)(tree), tree op)
+{
+ if (valueize && TREE_CODE (op) == SSA_NAME)
+ {
+ tree tem = valueize (op);
+ if (tem)
+ return tem;
+ }
+ return op;
+}
+
+
+/* Return true if pow(cst, x) should be optimized into exp(log(cst) * x).
+ As a workaround for SPEC CPU2017 628.pop2_s, don't do it if arg0
+ is an exact integer, arg1 = phi_res +/- cst1 and phi_res = PHI <cst2, ...>
+ where cst2 +/- cst1 is an exact integer, because then pow (arg0, arg1)
+ will likely be exact, while exp (log (arg0) * arg1) might be not.
+ Also don't do it if arg1 is phi_res above and cst2 is an exact integer. */
+
+static bool
+optimize_pow_to_exp (tree arg0, tree arg1)
+{
+ gcc_assert (TREE_CODE (arg0) == REAL_CST);
+ if (!real_isinteger (TREE_REAL_CST_PTR (arg0), TYPE_MODE (TREE_TYPE (arg0))))
+ return true;
+
+ if (TREE_CODE (arg1) != SSA_NAME)
+ return true;
+
+ gimple *def = SSA_NAME_DEF_STMT (arg1);
+ gphi *phi = dyn_cast <gphi *> (def);
+ tree cst1 = NULL_TREE;
+ enum tree_code code = ERROR_MARK;
+ if (!phi)
+ {
+ if (!is_gimple_assign (def))
+ return true;
+ code = gimple_assign_rhs_code (def);
+ switch (code)
+ {
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ break;
+ default:
+ return true;
+ }
+ if (TREE_CODE (gimple_assign_rhs1 (def)) != SSA_NAME
+ || TREE_CODE (gimple_assign_rhs2 (def)) != REAL_CST)
+ return true;
+
+ cst1 = gimple_assign_rhs2 (def);
+
+ phi = dyn_cast <gphi *> (SSA_NAME_DEF_STMT (gimple_assign_rhs1 (def)));
+ if (!phi)
+ return true;
+ }
+
+ tree cst2 = NULL_TREE;
+ int n = gimple_phi_num_args (phi);
+ for (int i = 0; i < n; i++)
+ {
+ tree arg = PHI_ARG_DEF (phi, i);
+ if (TREE_CODE (arg) != REAL_CST)
+ continue;
+ else if (cst2 == NULL_TREE)
+ cst2 = arg;
+ else if (!operand_equal_p (cst2, arg, 0))
+ return true;
+ }
+
+ if (cst1 && cst2)
+ cst2 = const_binop (code, TREE_TYPE (cst2), cst2, cst1);
+ if (cst2
+ && TREE_CODE (cst2) == REAL_CST
+ && real_isinteger (TREE_REAL_CST_PTR (cst2),
+ TYPE_MODE (TREE_TYPE (cst2))))
+ return false;
+ return true;
+}
diff --git a/gcc/gimple-match-head.c b/gcc/gimple-match-head.c
index 414007ec1f9..f6cffedbc2f 100644
--- a/gcc/gimple-match-head.c
+++ b/gcc/gimple-match-head.c
@@ -41,35 +41,25 @@ along with GCC; see the file COPYING3. If not see
#include "gimplify.h"
#include "optabs-tree.h"
#include "tree-eh.h"
+#include "gimple-match-head-common.h"
/* Forward declarations of the private auto-generated matchers.
They expect valueized operands in canonical order and do not
perform simplification of all-constant operands. */
-static bool gimple_simplify (gimple_match_op *, gimple_seq *, tree (*)(tree),
+extern bool gimple_simplify_generated (gimple_match_op *, gimple_seq *, tree (*)(tree),
code_helper, tree, tree);
-static bool gimple_simplify (gimple_match_op *, gimple_seq *, tree (*)(tree),
+extern bool gimple_simplify_generated (gimple_match_op *, gimple_seq *, tree (*)(tree),
code_helper, tree, tree, tree);
-static bool gimple_simplify (gimple_match_op *, gimple_seq *, tree (*)(tree),
+extern bool gimple_simplify_generated (gimple_match_op *, gimple_seq *, tree (*)(tree),
code_helper, tree, tree, tree, tree);
-static bool gimple_simplify (gimple_match_op *, gimple_seq *, tree (*)(tree),
+extern bool gimple_simplify_generated (gimple_match_op *, gimple_seq *, tree (*)(tree),
code_helper, tree, tree, tree, tree, tree);
-static bool gimple_simplify (gimple_match_op *, gimple_seq *, tree (*)(tree),
+extern bool gimple_simplify_generated (gimple_match_op *, gimple_seq *, tree (*)(tree),
code_helper, tree, tree, tree, tree, tree, tree);
-const unsigned int gimple_match_op::MAX_NUM_OPS;
-
-/* Return whether T is a constant that we'll dispatch to fold to
- evaluate fully constant expressions. */
-static inline bool
-constant_for_folding (tree t)
-{
- return (CONSTANT_CLASS_P (t)
- /* The following is only interesting to string builtins. */
- || (TREE_CODE (t) == ADDR_EXPR
- && TREE_CODE (TREE_OPERAND (t, 0)) == STRING_CST));
-}
+const unsigned int gimple_match_op::MAX_NUM_OPS;
/* Try to convert conditional operation ORIG_OP into an IFN_COND_*
operation. Return true on success, storing the new operation in NEW_OP. */
@@ -167,7 +157,7 @@ maybe_resimplify_conditional_op (gimple_seq *seq, gimple_match_op *res_op,
}
/* Helper that matches and simplifies the toplevel result from
- a gimple_simplify run (where we don't want to build
+ a gimple_simplify_generated run (where we don't want to build
a stmt in case it's used in in-place folding). Replaces
RES_OP with a simplified and/or canonicalized result and
returns whether any change was made. */
@@ -211,7 +201,7 @@ gimple_resimplify1 (gimple_seq *seq, gimple_match_op *res_op,
++depth;
gimple_match_op res_op2 (*res_op);
- if (gimple_simplify (&res_op2, seq, valueize,
+ if (gimple_simplify_generated (&res_op2, seq, valueize,
res_op->code, res_op->type, res_op->ops[0]))
{
--depth;
@@ -227,7 +217,7 @@ gimple_resimplify1 (gimple_seq *seq, gimple_match_op *res_op,
}
/* Helper that matches and simplifies the toplevel result from
- a gimple_simplify run (where we don't want to build
+ a gimple_simplify_generated run (where we don't want to build
a stmt in case it's used in in-place folding). Replaces
RES_OP with a simplified and/or canonicalized result and
returns whether any change was made. */
@@ -282,7 +272,7 @@ gimple_resimplify2 (gimple_seq *seq, gimple_match_op *res_op,
++depth;
gimple_match_op res_op2 (*res_op);
- if (gimple_simplify (&res_op2, seq, valueize,
+ if (gimple_simplify_generated (&res_op2, seq, valueize,
res_op->code, res_op->type,
res_op->ops[0], res_op->ops[1]))
{
@@ -299,7 +289,7 @@ gimple_resimplify2 (gimple_seq *seq, gimple_match_op *res_op,
}
/* Helper that matches and simplifies the toplevel result from
- a gimple_simplify run (where we don't want to build
+ a gimple_simplify_generated run (where we don't want to build
a stmt in case it's used in in-place folding). Replaces
RES_OP with a simplified and/or canonicalized result and
returns whether any change was made. */
@@ -353,7 +343,7 @@ gimple_resimplify3 (gimple_seq *seq, gimple_match_op *res_op,
++depth;
gimple_match_op res_op2 (*res_op);
- if (gimple_simplify (&res_op2, seq, valueize,
+ if (gimple_simplify_generated (&res_op2, seq, valueize,
res_op->code, res_op->type,
res_op->ops[0], res_op->ops[1], res_op->ops[2]))
{
@@ -370,7 +360,7 @@ gimple_resimplify3 (gimple_seq *seq, gimple_match_op *res_op,
}
/* Helper that matches and simplifies the toplevel result from
- a gimple_simplify run (where we don't want to build
+ a gimple_simplify_generated run (where we don't want to build
a stmt in case it's used in in-place folding). Replaces
RES_OP with a simplified and/or canonicalized result and
returns whether any change was made. */
@@ -393,7 +383,7 @@ gimple_resimplify4 (gimple_seq *seq, gimple_match_op *res_op,
++depth;
gimple_match_op res_op2 (*res_op);
- if (gimple_simplify (&res_op2, seq, valueize,
+ if (gimple_simplify_generated (&res_op2, seq, valueize,
res_op->code, res_op->type,
res_op->ops[0], res_op->ops[1], res_op->ops[2],
res_op->ops[3]))
@@ -411,7 +401,7 @@ gimple_resimplify4 (gimple_seq *seq, gimple_match_op *res_op,
}
/* Helper that matches and simplifies the toplevel result from
- a gimple_simplify run (where we don't want to build
+ a gimple_simplify_generated run (where we don't want to build
a stmt in case it's used in in-place folding). Replaces
RES_OP with a simplified and/or canonicalized result and
returns whether any change was made. */
@@ -423,7 +413,7 @@ gimple_resimplify5 (gimple_seq *seq, gimple_match_op *res_op,
/* No constant folding is defined for five-operand functions. */
gimple_match_op res_op2 (*res_op);
- if (gimple_simplify (&res_op2, seq, valueize,
+ if (gimple_simplify_generated (&res_op2, seq, valueize,
res_op->code, res_op->type,
res_op->ops[0], res_op->ops[1], res_op->ops[2],
res_op->ops[3], res_op->ops[4]))
@@ -616,7 +606,7 @@ gimple_simplify (enum tree_code code, tree type,
}
gimple_match_op res_op;
- if (!gimple_simplify (&res_op, seq, valueize, code, type, op0))
+ if (!gimple_simplify_generated (&res_op, seq, valueize, code, type, op0))
return NULL_TREE;
return maybe_push_res_to_seq (&res_op, seq);
}
@@ -648,7 +638,7 @@ gimple_simplify (enum tree_code code, tree type,
}
gimple_match_op res_op;
- if (!gimple_simplify (&res_op, seq, valueize, code, type, op0, op1))
+ if (!gimple_simplify_generated (&res_op, seq, valueize, code, type, op0, op1))
return NULL_TREE;
return maybe_push_res_to_seq (&res_op, seq);
}
@@ -676,7 +666,7 @@ gimple_simplify (enum tree_code code, tree type,
std::swap (op0, op1);
gimple_match_op res_op;
- if (!gimple_simplify (&res_op, seq, valueize, code, type, op0, op1, op2))
+ if (!gimple_simplify_generated (&res_op, seq, valueize, code, type, op0, op1, op2))
return NULL_TREE;
return maybe_push_res_to_seq (&res_op, seq);
}
@@ -696,7 +686,7 @@ gimple_simplify (combined_fn fn, tree type,
}
gimple_match_op res_op;
- if (!gimple_simplify (&res_op, seq, valueize, fn, type, arg0))
+ if (!gimple_simplify_generated (&res_op, seq, valueize, fn, type, arg0))
return NULL_TREE;
return maybe_push_res_to_seq (&res_op, seq);
}
@@ -717,7 +707,7 @@ gimple_simplify (combined_fn fn, tree type,
}
gimple_match_op res_op;
- if (!gimple_simplify (&res_op, seq, valueize, fn, type, arg0, arg1))
+ if (!gimple_simplify_generated (&res_op, seq, valueize, fn, type, arg0, arg1))
return NULL_TREE;
return maybe_push_res_to_seq (&res_op, seq);
}
@@ -739,29 +729,11 @@ gimple_simplify (combined_fn fn, tree type,
}
gimple_match_op res_op;
- if (!gimple_simplify (&res_op, seq, valueize, fn, type, arg0, arg1, arg2))
+ if (!gimple_simplify_generated (&res_op, seq, valueize, fn, type, arg0, arg1, arg2))
return NULL_TREE;
return maybe_push_res_to_seq (&res_op, seq);
}
-/* Helper for gimple_simplify valueizing OP using VALUEIZE and setting
- VALUEIZED to true if valueization changed OP. */
-
-static inline tree
-do_valueize (tree op, tree (*valueize)(tree), bool &valueized)
-{
- if (valueize && TREE_CODE (op) == SSA_NAME)
- {
- tree tem = valueize (op);
- if (tem && tem != op)
- {
- op = tem;
- valueized = true;
- }
- }
- return op;
-}
-
/* If RES_OP is a call to a conditional internal function, try simplifying
the associated unconditional operation and using the result to build
a new conditional operation. For example, if RES_OP is:
@@ -1019,140 +991,3 @@ gimple_simplify (gimple *stmt, gimple_match_op *res_op, gimple_seq *seq,
return false;
}
-
-
-/* Helper for the autogenerated code, valueize OP. */
-
-inline tree
-do_valueize (tree (*valueize)(tree), tree op)
-{
- if (valueize && TREE_CODE (op) == SSA_NAME)
- {
- tree tem = valueize (op);
- if (tem)
- return tem;
- }
- return op;
-}
-
-/* Helper for the autogenerated code, get at the definition of NAME when
- VALUEIZE allows that. */
-
-inline gimple *
-get_def (tree (*valueize)(tree), tree name)
-{
- if (valueize && ! valueize (name))
- return NULL;
- return SSA_NAME_DEF_STMT (name);
-}
-
-/* Routine to determine if the types T1 and T2 are effectively
- the same for GIMPLE. If T1 or T2 is not a type, the test
- applies to their TREE_TYPE. */
-
-static inline bool
-types_match (tree t1, tree t2)
-{
- if (!TYPE_P (t1))
- t1 = TREE_TYPE (t1);
- if (!TYPE_P (t2))
- t2 = TREE_TYPE (t2);
-
- return types_compatible_p (t1, t2);
-}
-
-/* Return if T has a single use. For GIMPLE, we also allow any
- non-SSA_NAME (ie constants) and zero uses to cope with uses
- that aren't linked up yet. */
-
-static inline bool
-single_use (tree t)
-{
- return TREE_CODE (t) != SSA_NAME || has_zero_uses (t) || has_single_use (t);
-}
-
-/* Return true if math operations should be canonicalized,
- e.g. sqrt(sqrt(x)) -> pow(x, 0.25). */
-
-static inline bool
-canonicalize_math_p ()
-{
- return !cfun || (cfun->curr_properties & PROP_gimple_opt_math) == 0;
-}
-
-/* Return true if math operations that are beneficial only after
- vectorization should be canonicalized. */
-
-static inline bool
-canonicalize_math_after_vectorization_p ()
-{
- return !cfun || (cfun->curr_properties & PROP_gimple_lvec) != 0;
-}
-
-/* Return true if pow(cst, x) should be optimized into exp(log(cst) * x).
- As a workaround for SPEC CPU2017 628.pop2_s, don't do it if arg0
- is an exact integer, arg1 = phi_res +/- cst1 and phi_res = PHI <cst2, ...>
- where cst2 +/- cst1 is an exact integer, because then pow (arg0, arg1)
- will likely be exact, while exp (log (arg0) * arg1) might be not.
- Also don't do it if arg1 is phi_res above and cst2 is an exact integer. */
-
-static bool
-optimize_pow_to_exp (tree arg0, tree arg1)
-{
- gcc_assert (TREE_CODE (arg0) == REAL_CST);
- if (!real_isinteger (TREE_REAL_CST_PTR (arg0), TYPE_MODE (TREE_TYPE (arg0))))
- return true;
-
- if (TREE_CODE (arg1) != SSA_NAME)
- return true;
-
- gimple *def = SSA_NAME_DEF_STMT (arg1);
- gphi *phi = dyn_cast <gphi *> (def);
- tree cst1 = NULL_TREE;
- enum tree_code code = ERROR_MARK;
- if (!phi)
- {
- if (!is_gimple_assign (def))
- return true;
- code = gimple_assign_rhs_code (def);
- switch (code)
- {
- case PLUS_EXPR:
- case MINUS_EXPR:
- break;
- default:
- return true;
- }
- if (TREE_CODE (gimple_assign_rhs1 (def)) != SSA_NAME
- || TREE_CODE (gimple_assign_rhs2 (def)) != REAL_CST)
- return true;
-
- cst1 = gimple_assign_rhs2 (def);
-
- phi = dyn_cast <gphi *> (SSA_NAME_DEF_STMT (gimple_assign_rhs1 (def)));
- if (!phi)
- return true;
- }
-
- tree cst2 = NULL_TREE;
- int n = gimple_phi_num_args (phi);
- for (int i = 0; i < n; i++)
- {
- tree arg = PHI_ARG_DEF (phi, i);
- if (TREE_CODE (arg) != REAL_CST)
- continue;
- else if (cst2 == NULL_TREE)
- cst2 = arg;
- else if (!operand_equal_p (cst2, arg, 0))
- return true;
- }
-
- if (cst1 && cst2)
- cst2 = const_binop (code, TREE_TYPE (cst2), cst2, cst1);
- if (cst2
- && TREE_CODE (cst2) == REAL_CST
- && real_isinteger (TREE_REAL_CST_PTR (cst2),
- TYPE_MODE (TREE_TYPE (cst2))))
- return false;
- return true;
-}
diff --git a/gcc/splitter.cc b/gcc/splitter.cc
new file mode 100644
index 00000000000..528d814b9a9
--- /dev/null
+++ b/gcc/splitter.cc
@@ -0,0 +1,357 @@
+#include <sstream>
+#include <string>
+#include <fstream>
+#include <vector>
+#include <map>
+#include <algorithm>
+
+#include <iostream>
+#include <list>
+#include <stack>
+
+#define NIL -1
+
+using namespace std;
+
+// A class that represents an directed graph
+class Graph
+{
+ int V; // No. of vertices
+ list<int> *adj; // A dynamic array of adjacency lists
+
+ // A Recursive DFS based function used by SCC()
+ void SCCUtil(int u, int disc[], int low[],
+ stack<int> *st, bool stackMember[]);
+public:
+ Graph(int V); // Constructor
+ void addEdge(int v, int w); // function to add an edge to graph
+ void SCC(); // prints strongly connected components
+
+ vector<vector<int>> components;
+};
+
+Graph::Graph(int V)
+{
+ this->V = V;
+ adj = new list<int>[V];
+}
+
+void Graph::addEdge(int v, int w)
+{
+ adj[v].push_back(w);
+}
+
+// A recursive function that finds and prints strongly connected
+// components using DFS traversal
+// u --> The vertex to be visited next
+// disc[] --> Stores discovery times of visited vertices
+// low[] -- >> earliest visited vertex (the vertex with minimum
+// discovery time) that can be reached from subtree
+// rooted with current vertex
+// *st -- >> To store all the connected ancestors (could be part
+// of SCC)
+// stackMember[] --> bit/index array for faster check whether
+// a node is in stack
+void Graph::SCCUtil(int u, int disc[], int low[], stack<int> *st,
+ bool stackMember[])
+{
+ // A static variable is used for simplicity, we can avoid use
+ // of static variable by passing a pointer.
+ static int time = 0;
+
+ // Initialize discovery time and low value
+ disc[u] = low[u] = ++time;
+ st->push(u);
+ stackMember[u] = true;
+
+ // Go through all vertices adjacent to this
+ list<int>::iterator i;
+ for (i = adj[u].begin(); i != adj[u].end(); ++i)
+ {
+ int v = *i; // v is current adjacent of 'u'
+
+ // If v is not visited yet, then recur for it
+ if (disc[v] == -1)
+ {
+ SCCUtil(v, disc, low, st, stackMember);
+
+ // Check if the subtree rooted with 'v' has a
+ // connection to one of the ancestors of 'u'
+ // Case 1 (per above discussion on Disc and Low value)
+ low[u] = min(low[u], low[v]);
+ }
+
+ // Update low value of 'u' only of 'v' is still in stack
+ // (i.e. it's a back edge, not cross edge).
+ // Case 2 (per above discussion on Disc and Low value)
+ else if (stackMember[v] == true)
+ low[u] = min(low[u], disc[v]);
+ }
+
+ // head node found, pop the stack and print an SCC
+ int w = 0; // To store stack extracted vertices
+ if (low[u] == disc[u])
+ {
+ vector<int> component;
+ while (st->top() != u)
+ {
+ w = (int) st->top();
+ component.push_back (w);
+ stackMember[w] = false;
+ st->pop();
+ }
+ w = (int) st->top();
+ component.push_back (w);
+ components.push_back (component);
+ stackMember[w] = false;
+ st->pop();
+ }
+}
+
+// The function to do DFS traversal. It uses SCCUtil()
+void Graph::SCC()
+{
+ int *disc = new int[V];
+ int *low = new int[V];
+ bool *stackMember = new bool[V];
+ stack<int> *st = new stack<int>();
+
+ // Initialize disc and low, and stackMember arrays
+ for (int i = 0; i < V; i++)
+ {
+ disc[i] = NIL;
+ low[i] = NIL;
+ stackMember[i] = false;
+ }
+
+ // Call the recursive helper function to find strongly
+ // connected components in DFS tree with vertex 'i'
+ for (int i = 0; i < V; i++)
+ if (disc[i] == NIL)
+ SCCUtil(i, disc, low, st, stackMember);
+}
+
+using namespace std;
+
+struct function_entry
+{
+ function_entry (string name, unsigned lineno_start, unsigned id):
+ m_name (name), m_lineno_start (lineno_start), m_id (id),
+ m_callees ()
+ {}
+
+ unsigned get_loc ()
+ {
+ return m_lineno_end - m_lineno_start;
+ }
+
+ string m_name;
+ unsigned m_lineno_start;
+ unsigned m_lineno_end;
+ unsigned m_id;
+ vector<unsigned> m_callees;
+};
+
+map<string, unsigned> fn_to_index_map;
+vector<function_entry *> functions;
+vector<string> lines;
+
+static unsigned
+get_id_for_fname (string fname)
+{
+ map<string, unsigned>::iterator it = fn_to_index_map.find (fname);
+ if (it != fn_to_index_map.end ())
+ return it->second;
+ else
+ {
+ unsigned id = fn_to_index_map.size ();
+ fn_to_index_map[fname] = id;
+ return id;
+ }
+}
+
+struct function_component
+{
+ function_component (vector<int> function_ids):
+ m_function_ids (function_ids)
+ {}
+
+ void print()
+ {
+ for (unsigned i = 0; i < m_function_ids.size (); i++)
+ printf ("%s ", functions[m_function_ids[i]]->m_name.c_str ());
+ printf ("\n");
+ }
+
+ unsigned get_total_loc ()
+ {
+ unsigned loc = 0;
+ for (unsigned i = 0; i < m_function_ids.size (); i++)
+ loc += functions[m_function_ids[i]]->get_loc ();
+ return loc;
+ }
+
+ void write (ofstream &s)
+ {
+ sort (m_function_ids.begin (), m_function_ids.end ());
+ for (unsigned i = 0; i < m_function_ids.size (); i++)
+ {
+ function_entry *f = functions[m_function_ids[i]];
+ for (unsigned j = f->m_lineno_start; j <= f->m_lineno_end; j++)
+ s << lines[j] << endl;
+ s << endl;
+ }
+ }
+
+ vector<int> m_function_ids;
+};
+
+bool component_size_cmp (function_component *a, function_component *b)
+{
+ return a->get_total_loc () < b->get_total_loc ();
+}
+
+vector<function_component *> components;
+
+int
+main (int argc, char **argv)
+{
+ if (argc != 2)
+ return -1;
+
+ string type (argv[1]);
+
+ ifstream infile(type + "-match.c");
+ ofstream header(type + "-match-header.c");
+ ofstream footer(type + "-match-part-footer.c");
+ footer << "#include \"" << type << "-match-header.c\"" << endl;
+
+ string line;
+ unsigned lineno = 0;
+ bool in_split = false;
+ bool header_done = false;
+
+ while (getline(infile, line))
+ {
+ string fnbegin ("// split-fn-begin:");
+ string fnend ("// split-fn-end");
+ string call ("// call-fn:");
+ lines.push_back (line);
+
+ if (line.find(fnbegin) != string::npos)
+ {
+ in_split = true;
+ header_done = true;
+ string fname = line.substr (fnbegin.length ());
+ functions.push_back (new function_entry (fname, lineno,
+ get_id_for_fname (fname)));
+ }
+ else if (line.find (fnend) != string::npos)
+ {
+ functions.back ()->m_lineno_end = lineno;
+ in_split = false;
+ }
+ else if (line.find (call) != string::npos)
+ {
+ string fname = line.substr (call.length ());
+ functions.back ()->m_callees.push_back (get_id_for_fname (fname));
+ }
+ else if (!in_split && !line.empty ())
+ {
+ if (header_done)
+ footer << line << endl;
+ else
+ header << line << endl;
+ }
+
+ lineno++;
+ }
+
+ /*
+ for (unsigned i = 0; i < functions.size (); i++)
+ {
+ function_entry *f = functions[i];
+ fprintf (stderr, "%d %s: %d\n",
+ f->m_lineno_end - f->m_lineno_start,
+ f->m_name.c_str (), f->m_callees.size ());
+ }
+ */
+
+ /* Create graph and compute SCC. */
+ Graph g (functions.size ());
+ for (unsigned i = 0; i < functions.size (); i++)
+ {
+ function_entry *f = functions[i];
+ for (unsigned j = 0; j < f->m_callees.size (); j++)
+ {
+ g.addEdge (f->m_id, f->m_callees[j]);
+ g.addEdge (f->m_callees[j], f->m_id);
+ }
+ }
+ g.SCC ();
+
+ for (unsigned i = 0; i < g.components.size (); i++)
+ components.push_back (new function_component(g.components[i]));
+
+ sort (components.begin (), components.end (), component_size_cmp);
+
+ unsigned total_loc = 0;
+ for (unsigned i = 0; i < components.size (); i++)
+ {
+// components[i]->print();
+ total_loc += components[i]->get_total_loc ();
+ }
+
+ printf ("Total # of functions: %ld, total LOC: %u\n", functions.size (),
+ total_loc);
+
+ vector<vector<function_component *>> groups;
+
+ unsigned parts = 4;
+ unsigned component_size = total_loc / parts;
+ if (components.back ()->get_total_loc () > component_size)
+ component_size = components.back ()->get_total_loc ();
+
+ for (unsigned i = 0; i < parts; i++)
+ {
+ unsigned space = component_size;
+ vector<function_component *> group;
+ for (int j = components.size () - 1; j >= 0; j--)
+ {
+ function_component *c = components[j];
+ unsigned loc = c->get_total_loc ();
+ if (space >= loc || (i == parts - 1))
+ {
+// fprintf (stderr, "adding %d to group %d\n", loc, i);
+ components.erase (components.begin () + j);
+ space -= loc;
+ group.push_back (c);
+ }
+ }
+
+ groups.push_back (group);
+ }
+
+ for (unsigned i = 0; i < groups.size (); i++)
+ {
+ string name = type + "-match-part-" + std::to_string (i) + ".c";
+ ofstream s (name);
+ s << "#include \"" << type << "-match-header.c\"" << endl;
+
+ unsigned loc = 0;
+ for (unsigned j = 0; j < groups[i].size (); j++)
+ {
+ function_component *c = groups[i][j];
+ loc += c->get_total_loc ();
+ c->write (s);
+ }
+ s.close ();
+
+ fprintf (stderr, "written %d LOC functions to %s\n", loc, name.c_str ());
+ }
+
+ header.close ();
+ footer.close ();
+
+ return 0;
+}
--
2.18.0
next prev parent reply other threads:[~2018-09-04 15:07 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-04-25 11:44 Richard Biener
2018-04-25 12:26 ` Richard Biener
2018-04-25 12:46 ` Richard Biener
2018-04-25 13:16 ` Martin Liška
2018-09-03 12:27 ` Martin Liška
2018-09-03 12:41 ` Richard Biener
2018-09-03 12:54 ` Martin Liška
2018-09-03 13:50 ` Martin Liška
2018-09-03 14:01 ` Richard Biener
2018-09-03 14:27 ` Martin Liška
2018-09-03 14:43 ` Richard Biener
2018-09-04 15:07 ` Martin Liška [this message]
2018-09-10 11:43 ` Martin Liška
2019-04-29 15:21 ` Martin Liška
2019-05-02 13:18 ` Richard Biener
2019-05-02 17:00 ` Segher Boessenkool
2019-05-02 17:41 ` Richard Biener
2019-05-02 18:14 ` Segher Boessenkool
2019-05-02 19:04 ` Richard Biener
2019-05-06 12:59 ` Martin Liška
2019-05-06 13:36 ` Richard Biener
2019-05-06 13:51 ` Martin Liška
2019-05-06 15:10 ` Segher Boessenkool
2019-05-06 12:56 ` Martin Liška
2019-05-06 13:32 ` Richard Biener
2019-05-06 13:50 ` Martin Liška
2019-04-29 14:41 ` Martin Liška
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=c9c0ee2c-79dc-8374-b55b-655fd2e161c6@suse.cz \
--to=mliska@suse.cz \
--cc=gcc-patches@gcc.gnu.org \
--cc=rguenther@suse.de \
/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).