This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
make genattrtab generate smaller code
- From: Michael Matz <matz at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Fri, 5 Sep 2003 21:15:24 +0200 (CEST)
- Subject: make genattrtab generate smaller code
Hi,
this patch makes the code in insn-attrtab.c cache the attributes.
It currently generates code like:
enum attr_x get_attr_lala (rtx insn) {
switch (recog_memoized(insn)) {
case xxx:
if (bla && get_attr_memory(insn) == XXX) {
} else if (blubb && get_attr_memory(insn) == XXX) {
} else if (bla2 && get_attr_memory(insn) == YYY) {
} else {
}
default:
} }
This patch moves all the get_attr_xxx calls inside the if()s to the front
of the function by caching the results, in order to save several
hundred function calls, i.e. like:
enum attr_x get_attr_lala (rtx insn) {
enum attr_memory attr_memory = get_attr_memory(insn);
switch (recog_memoized(insn)) {
case xxx:
if (bla && attr_memory == XXX) {
} else if (blubb && attr_memory == XXX) {
} else if (bla2 && attr_memory == YYY) {
} else {
}
default:
} }
A result of this is (on x86):
matz suse 1601778 2003-09-05 14:07 insn-attrtab.old.c
matz suse 793008 2003-09-05 15:01 insn-attrtab.old.o
matz suse 1550943 2003-09-05 20:56 insn-attrtab.c
matz suse 699704 2003-09-05 20:56 insn-attrtab.o
% size insn-attrtab.o insn-attrtab.old.o
text data bss dec hex filename
325144 8 892 326044 4f99c insn-attrtab.o
374060 8 892 374960 5b8b0 insn-attrtab.old.o
Bootstraptimes don't change much. Time for booting C,C++ (-j4)
HEAD
real 13m39.093s
user 39m22.830s
sys 2m17.970s
HEAD+patch
real 13m16.332s
user 38m56.860s
sys 2m20.070s
Bootstrapped (all langs - treelang), no regressions, i686-linux.
I also experimented with merging the multiple test on which_alternative to
use '&', ala
if ((which_alternative == 1) || (which_alternative == 2))
-->
if ((1 << which_alternative) & 0x6)
but this didn't result in smaller or faster code. Maybe I should do this
only if at least three bits are set in the mask (instead of two in my
experiments).
Ciao,
Michael.
2003-09-05 Michael Matz <matz@suse.de>
* genattrtab.c (write_cache_used_attributes): New.
(write_attr_get, write_eligible_delay,
write_complex_function): Use it.
(write_attr_set): Calling write_test_expr() with caching flag.
Index: genattrtab.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/genattrtab.c,v
retrieving revision 1.136
diff -u -p -r1.136 genattrtab.c
--- genattrtab.c 22 Aug 2003 06:45:14 -0000 1.136
+++ genattrtab.c 5 Sep 2003 18:54:38 -0000
@@ -435,6 +435,7 @@ static rtx eliminate_known_true (rtx, rt
static void write_attr_set (struct attr_desc *, int, rtx,
const char *, const char *, rtx,
int, int);
+static void write_cache_used_attributes (struct attr_desc *);
static void write_attr_case (struct attr_desc *, struct attr_value *,
int, const char *, const char *, int, rtx);
static void write_unit_name (const char *, int, const char *);
@@ -4749,6 +4750,23 @@ walk_attr_value (rtx exp)
}
}
+static void
+write_cache_used_attributes (struct attr_desc *attr)
+{
+ struct attr_value *av;
+ struct attr_desc *attr2;
+ int i;
+
+ printf ("{ ");
+ for (i = 0; i < MAX_ATTRS_INDEX; ++i)
+ for (attr2 = attrs[i]; attr2; attr2 = attr2->next)
+ if (!attr2->is_const)
+ for (av = attr->first_value; av; av = av->next)
+ if (av->num_insns != 0)
+ if (write_expr_attr_cache (av->value, attr2))
+ break;
+}
+
/* Write out a function to obtain the attribute for a given INSN. */
static void
@@ -4782,13 +4800,14 @@ write_attr_get (struct attr_desc *attr)
printf ("get_attr_%s (void)\n", attr->name);
printf ("{\n");
+ write_cache_used_attributes (attr);
for (av = attr->first_value; av; av = av->next)
if (av->num_insns != 0)
write_attr_set (attr, 2, av->value, "return", ";",
true_rtx, av->first_insn->insn_code,
av->first_insn->insn_index);
- printf ("}\n\n");
+ printf ("}}\n\n");
return;
}
@@ -4814,6 +4833,7 @@ write_attr_get (struct attr_desc *attr)
}
else
{
+ write_cache_used_attributes (attr);
printf (" switch (recog_memoized (insn))\n");
printf (" {\n");
@@ -4822,7 +4842,7 @@ write_attr_get (struct attr_desc *attr)
write_attr_case (attr, av, 1, "return", ";", 4, true_rtx);
write_attr_case (attr, common_av, 0, "return", ";", 4, true_rtx);
- printf (" }\n}\n\n");
+ printf (" }}\n}\n\n");
}
}
@@ -4907,7 +4927,7 @@ write_attr_set (struct attr_desc *attr,
write_indent (indent);
printf ("%sif ", first_if ? "" : "else ");
first_if = 0;
- write_test_expr (testexp, 0);
+ write_test_expr (testexp, 2);
printf ("\n");
write_indent (indent + 2);
printf ("{\n");
@@ -5284,6 +5304,7 @@ write_eligible_delay (const char *kind)
common_av = find_most_used (attr);
printf (" insn = delay_insn;\n");
+ write_cache_used_attributes (attr);
printf (" switch (recog_memoized (insn))\n");
printf (" {\n");
@@ -5293,7 +5314,7 @@ write_eligible_delay (const char *kind)
write_attr_case (attr, av, 1, "slot +=", str, 4, true_rtx);
write_attr_case (attr, common_av, 0, "slot +=", str, 4, true_rtx);
- printf (" }\n\n");
+ printf (" }}\n\n");
/* Ensure matched. Otherwise, shouldn't have been called. */
printf (" if (slot < %d)\n", max_slots);
@@ -5303,21 +5324,22 @@ write_eligible_delay (const char *kind)
/* If just one type of delay slot, write simple switch. */
if (num_delays == 1 && max_slots == 1)
{
- printf (" insn = candidate_insn;\n");
- printf (" switch (recog_memoized (insn))\n");
- printf (" {\n");
-
attr = find_attr ("*delay_1_0", 0);
if (! attr)
abort ();
common_av = find_most_used (attr);
+ printf (" insn = candidate_insn;\n");
+ write_cache_used_attributes (attr);
+ printf (" switch (recog_memoized (insn))\n");
+ printf (" {\n");
+
for (av = attr->first_value; av; av = av->next)
if (av != common_av)
write_attr_case (attr, av, 1, "return", ";", 4, true_rtx);
write_attr_case (attr, common_av, 0, "return", ";", 4, true_rtx);
- printf (" }\n");
+ printf (" }}\n");
}
else
@@ -5331,23 +5353,24 @@ write_eligible_delay (const char *kind)
for (delay = delays; delay; delay = delay->next)
for (i = 0; i < XVECLEN (delay->def, 1); i += 3)
{
- printf (" case %d:\n",
- (i / 3) + (num_delays == 1 ? 0 : delay->num * max_slots));
- printf (" switch (recog_memoized (insn))\n");
- printf ("\t{\n");
-
sprintf (str, "*%s_%d_%d", kind, delay->num, i / 3);
attr = find_attr (str, 0);
if (! attr)
abort ();
common_av = find_most_used (attr);
+ printf (" case %d:\n",
+ (i / 3) + (num_delays == 1 ? 0 : delay->num * max_slots));
+ write_cache_used_attributes (attr);
+ printf (" switch (recog_memoized (insn))\n");
+ printf ("\t{\n");
+
for (av = attr->first_value; av; av = av->next)
if (av != common_av)
write_attr_case (attr, av, 1, "return", ";", 8, true_rtx);
write_attr_case (attr, common_av, 0, "return", ";", 8, true_rtx);
- printf (" }\n");
+ printf (" }}\n");
}
printf (" default:\n");
@@ -5444,6 +5467,15 @@ write_complex_function (struct function_
int using_case;
int i;
+ /* Write the `switch' statement to get the case value. */
+ if (strlen (unit->name) + sizeof "*_cases" > 256)
+ abort ();
+ sprintf (str, "*%s_cases", unit->name);
+ case_attr = find_attr (str, 0);
+ if (! case_attr)
+ abort ();
+ common_av = find_most_used (case_attr);
+
printf ("static int\n");
printf ("%s_unit_%s (rtx executing_insn, rtx candidate_insn)\n",
unit->name, name);
@@ -5451,18 +5483,10 @@ write_complex_function (struct function_
printf (" rtx insn;\n");
printf (" int casenum;\n\n");
printf (" insn = executing_insn;\n");
+ write_cache_used_attributes (case_attr);
printf (" switch (recog_memoized (insn))\n");
printf (" {\n");
- /* Write the `switch' statement to get the case value. */
- if (strlen (unit->name) + sizeof "*_cases" > 256)
- abort ();
- sprintf (str, "*%s_cases", unit->name);
- case_attr = find_attr (str, 0);
- if (! case_attr)
- abort ();
- common_av = find_most_used (case_attr);
-
for (av = case_attr->first_value; av; av = av->next)
if (av != common_av)
write_attr_case (case_attr, av, 1,
@@ -5470,7 +5494,7 @@ write_complex_function (struct function_
write_attr_case (case_attr, common_av, 0,
"casenum =", ";", 4, unit->condexp);
- printf (" }\n\n");
+ printf (" }}\n\n");
/* Now write an outer switch statement on each case. Then write
the tests on the executing function within each. */
@@ -5496,6 +5520,7 @@ write_complex_function (struct function_
if (! attr)
abort ();
+ write_cache_used_attributes (attr);
/* If single value, just write it. */
value = find_single_value (attr);
if (value)
@@ -5515,6 +5540,7 @@ write_complex_function (struct function_
"return", ";", 8, unit->condexp);
printf (" }\n\n");
}
+ printf ("}\n");
}
/* This default case should not be needed, but gcc's analysis is not