From: Jan Hubicka <jh@suse.cz>
To: Paolo Bonzini <bonzini@gnu.org>
Cc: Richard Guenther <richard.guenther@gmail.com>,
Jan Hubicka <jh@suse.cz>, GCC Patches <gcc-patches@gcc.gnu.org>
Subject: Re: Reduce startup cost of compiler (patch 2)
Date: Tue, 24 Jul 2007 15:14:00 -0000 [thread overview]
Message-ID: <20070724150127.GE10270@kam.mff.cuni.cz> (raw)
In-Reply-To: <46A5A7D8.6070503@gnu.org>
>
> >>Bootstrapped/regtested i686-linux?
> >
> >Nice! Yes, this is ok.
>
> all_match is write only, though:
Uh, good catch. I was testing if removing that trick slows down startup
(and it does) and forgot to put it back. I am re-testing the attached
patch which I will commit if it passes.
Honza
Index: regclass.c
===================================================================
*** regclass.c (revision 126859)
--- regclass.c (working copy)
*************** bool have_regs_of_mode [MAX_MACHINE_MODE
*** 214,233 ****
static char contains_reg_of_mode [N_REG_CLASSES] [MAX_MACHINE_MODE];
/* Maximum cost of moving from a register in one class to a register in
another class. Based on REGISTER_MOVE_COST. */
! static int move_cost[MAX_MACHINE_MODE][N_REG_CLASSES][N_REG_CLASSES];
/* Similar, but here we don't have to move if the first index is a subset
of the second so in that case the cost is zero. */
! static int may_move_in_cost[MAX_MACHINE_MODE][N_REG_CLASSES][N_REG_CLASSES];
/* Similar, but here we don't have to move if the first index is a superset
of the second so in that case the cost is zero. */
! static int may_move_out_cost[MAX_MACHINE_MODE][N_REG_CLASSES][N_REG_CLASSES];
#ifdef FORBIDDEN_INC_DEC_CLASSES
--- 214,235 ----
static char contains_reg_of_mode [N_REG_CLASSES] [MAX_MACHINE_MODE];
+ typedef unsigned short move_table[N_REG_CLASSES];
+
/* Maximum cost of moving from a register in one class to a register in
another class. Based on REGISTER_MOVE_COST. */
! static move_table *move_cost[MAX_MACHINE_MODE];
/* Similar, but here we don't have to move if the first index is a subset
of the second so in that case the cost is zero. */
! static move_table *may_move_in_cost[MAX_MACHINE_MODE];
/* Similar, but here we don't have to move if the first index is a superset
of the second so in that case the cost is zero. */
! static move_table *may_move_out_cost[MAX_MACHINE_MODE];
#ifdef FORBIDDEN_INC_DEC_CLASSES
*************** init_reg_sets (void)
*** 312,317 ****
--- 314,409 ----
#endif
}
+ /* Initialize may_move_cost and friends for mode M. */
+
+ static void
+ init_move_cost (enum machine_mode m)
+ {
+ static unsigned short last_move_cost[N_REG_CLASSES][N_REG_CLASSES];
+ static int last_mode = -1;
+ bool all_match = true;
+ unsigned int i, j;
+
+ gcc_assert (have_regs_of_mode[m]);
+ for (i = 0; i < N_REG_CLASSES; i++)
+ if (contains_reg_of_mode[i][m])
+ for (j = 0; j < N_REG_CLASSES; j++)
+ {
+ int cost;
+ if (!contains_reg_of_mode[j][m])
+ cost = 65535;
+ else
+ {
+ cost = REGISTER_MOVE_COST (m, i, j);
+ gcc_assert (cost < 65535);
+ }
+ all_match &= (last_move_cost[i][j] == cost);
+ last_move_cost[i][j] = cost;
+ }
+ if (all_match && last_mode != -1)
+ {
+ move_cost[m] = move_cost[last_mode];
+ may_move_in_cost[m] = may_move_in_cost[last_mode];
+ may_move_out_cost[m] = may_move_out_cost[last_mode];
+ return;
+ }
+ last_mode = m;
+ move_cost[m] = (move_table *)xmalloc (sizeof (move_table)
+ * N_REG_CLASSES);
+ may_move_in_cost[m] = (move_table *)xmalloc (sizeof (move_table)
+ * N_REG_CLASSES);
+ may_move_out_cost[m] = (move_table *)xmalloc (sizeof (move_table)
+ * N_REG_CLASSES);
+ for (i = 0; i < N_REG_CLASSES; i++)
+ if (contains_reg_of_mode[i][m])
+ for (j = 0; j < N_REG_CLASSES; j++)
+ {
+ int cost;
+ enum reg_class *p1, *p2;
+
+ if (last_move_cost[i][j] == 65535)
+ {
+ move_cost[m][i][j] = 65535;
+ may_move_in_cost[m][i][j] = 65535;
+ may_move_out_cost[m][i][j] = 65535;
+ }
+ else
+ {
+ cost = last_move_cost[i][j];
+
+ for (p2 = ®_class_subclasses[j][0];
+ *p2 != LIM_REG_CLASSES; p2++)
+ if (*p2 != i && contains_reg_of_mode[*p2][m])
+ cost = MAX (cost, move_cost[m][i][*p2]);
+
+ for (p1 = ®_class_subclasses[i][0];
+ *p1 != LIM_REG_CLASSES; p1++)
+ if (*p1 != j && contains_reg_of_mode[*p1][m])
+ cost = MAX (cost, move_cost[m][*p1][j]);
+
+ gcc_assert (cost <= 65535);
+ move_cost[m][i][j] = cost;
+
+ if (reg_class_subset_p (i, j))
+ may_move_in_cost[m][i][j] = 0;
+ else
+ may_move_in_cost[m][i][j] = cost;
+
+ if (reg_class_subset_p (j, i))
+ may_move_out_cost[m][i][j] = 0;
+ else
+ may_move_out_cost[m][i][j] = cost;
+ }
+ }
+ else
+ for (j = 0; j < N_REG_CLASSES; j++)
+ {
+ move_cost[m][i][j] = 65535;
+ may_move_in_cost[m][i][j] = 65535;
+ may_move_out_cost[m][i][j] = 65535;
+ }
+ }
+
/* After switches have been processed, which perhaps alter
`fixed_regs' and `call_used_regs', convert them to HARD_REG_SETs. */
*************** init_reg_sets_1 (void)
*** 476,548 ****
memset (have_regs_of_mode, 0, sizeof (have_regs_of_mode));
memset (contains_reg_of_mode, 0, sizeof (contains_reg_of_mode));
for (m = 0; m < (unsigned int) MAX_MACHINE_MODE; m++)
! for (i = 0; i < N_REG_CLASSES; i++)
! if ((unsigned) CLASS_MAX_NREGS (i, m) <= reg_class_size[i])
! for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
! if (!fixed_regs [j] && TEST_HARD_REG_BIT (reg_class_contents[i], j)
! && HARD_REGNO_MODE_OK (j, m))
! {
! contains_reg_of_mode [i][m] = 1;
! have_regs_of_mode [m] = 1;
! break;
! }
!
! /* Initialize the move cost table. Find every subset of each class
! and take the maximum cost of moving any subset to any other. */
!
! for (m = 0; m < (unsigned int) MAX_MACHINE_MODE; m++)
! if (have_regs_of_mode [m])
! {
! for (i = 0; i < N_REG_CLASSES; i++)
! if (contains_reg_of_mode [i][m])
! for (j = 0; j < N_REG_CLASSES; j++)
! {
! int cost;
! enum reg_class *p1, *p2;
!
! if (!contains_reg_of_mode [j][m])
! {
! move_cost[m][i][j] = 65536;
! may_move_in_cost[m][i][j] = 65536;
! may_move_out_cost[m][i][j] = 65536;
! }
! else
! {
! cost = REGISTER_MOVE_COST (m, i, j);
!
! for (p2 = ®_class_subclasses[j][0];
! *p2 != LIM_REG_CLASSES;
! p2++)
! if (*p2 != i && contains_reg_of_mode [*p2][m])
! cost = MAX (cost, move_cost [m][i][*p2]);
!
! for (p1 = ®_class_subclasses[i][0];
! *p1 != LIM_REG_CLASSES;
! p1++)
! if (*p1 != j && contains_reg_of_mode [*p1][m])
! cost = MAX (cost, move_cost [m][*p1][j]);
!
! move_cost[m][i][j] = cost;
!
! if (reg_class_subset_p (i, j))
! may_move_in_cost[m][i][j] = 0;
! else
! may_move_in_cost[m][i][j] = cost;
!
! if (reg_class_subset_p (j, i))
! may_move_out_cost[m][i][j] = 0;
! else
! may_move_out_cost[m][i][j] = cost;
! }
! }
! else
! for (j = 0; j < N_REG_CLASSES; j++)
! {
! move_cost[m][i][j] = 65536;
! may_move_in_cost[m][i][j] = 65536;
! may_move_out_cost[m][i][j] = 65536;
! }
! }
}
/* Compute the table of register modes.
--- 568,588 ----
memset (have_regs_of_mode, 0, sizeof (have_regs_of_mode));
memset (contains_reg_of_mode, 0, sizeof (contains_reg_of_mode));
for (m = 0; m < (unsigned int) MAX_MACHINE_MODE; m++)
! {
! HARD_REG_SET ok_regs;
! CLEAR_HARD_REG_SET (ok_regs);
! for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
! if (!fixed_regs [j] && HARD_REGNO_MODE_OK (j, m))
! SET_HARD_REG_BIT (ok_regs, j);
!
! for (i = 0; i < N_REG_CLASSES; i++)
! if ((unsigned) CLASS_MAX_NREGS (i, m) <= reg_class_size[i]
! && hard_reg_set_intersect_p (ok_regs, reg_class_contents[i]))
! {
! contains_reg_of_mode [i][m] = 1;
! have_regs_of_mode [m] = 1;
! }
! }
}
/* Compute the table of register modes.
*************** record_reg_classes (int n_alts, int n_op
*** 1465,1479 ****
copy, which is one instruction. */
struct costs *pp = &this_op_costs[i];
!
! for (class = 0; class < N_REG_CLASSES; class++)
! pp->cost[class]
! = ((recog_data.operand_type[i] != OP_OUT
! ? may_move_in_cost[mode][class][(int) classes[i]]
! : 0)
! + (recog_data.operand_type[i] != OP_IN
! ? may_move_out_cost[mode][(int) classes[i]][class]
! : 0));
/* If the alternative actually allows memory, make things
a bit cheaper since we won't need an extra insn to
--- 1505,1537 ----
copy, which is one instruction. */
struct costs *pp = &this_op_costs[i];
! move_table *intable = NULL;
! move_table *outtable = NULL;
! int op_class = (int) classes[i];
!
! if (!move_cost[mode])
! init_move_cost (mode);
! intable = may_move_in_cost[mode];
! outtable = may_move_out_cost[mode];
!
! /* The loop is performance critical, so unswitch it manually.
! */
! switch (recog_data.operand_type[i])
! {
! case OP_INOUT:
! for (class = 0; class < N_REG_CLASSES; class++)
! pp->cost[class] = (intable[class][op_class]
! + outtable[op_class][class]);
! break;
! case OP_IN:
! for (class = 0; class < N_REG_CLASSES; class++)
! pp->cost[class] = intable[class][op_class];
! break;
! case OP_OUT:
! for (class = 0; class < N_REG_CLASSES; class++)
! pp->cost[class] = outtable[op_class][class];
! break;
! }
/* If the alternative actually allows memory, make things
a bit cheaper since we won't need an extra insn to
*************** record_reg_classes (int n_alts, int n_op
*** 1691,1705 ****
else
{
struct costs *pp = &this_op_costs[i];
!
! for (class = 0; class < N_REG_CLASSES; class++)
! pp->cost[class]
! = ((recog_data.operand_type[i] != OP_OUT
! ? may_move_in_cost[mode][class][(int) classes[i]]
! : 0)
! + (recog_data.operand_type[i] != OP_IN
! ? may_move_out_cost[mode][(int) classes[i]][class]
! : 0));
/* If the alternative actually allows memory, make things
a bit cheaper since we won't need an extra insn to
--- 1749,1781 ----
else
{
struct costs *pp = &this_op_costs[i];
! move_table *intable = NULL;
! move_table *outtable = NULL;
! int op_class = (int) classes[i];
!
! if (!move_cost[mode])
! init_move_cost (mode);
! intable = may_move_in_cost[mode];
! outtable = may_move_out_cost[mode];
!
! /* The loop is performance critical, so unswitch it manually.
! */
! switch (recog_data.operand_type[i])
! {
! case OP_INOUT:
! for (class = 0; class < N_REG_CLASSES; class++)
! pp->cost[class] = (intable[class][op_class]
! + outtable[op_class][class]);
! break;
! case OP_IN:
! for (class = 0; class < N_REG_CLASSES; class++)
! pp->cost[class] = intable[class][op_class];
! break;
! case OP_OUT:
! for (class = 0; class < N_REG_CLASSES; class++)
! pp->cost[class] = outtable[op_class][class];
! break;
! }
/* If the alternative actually allows memory, make things
a bit cheaper since we won't need an extra insn to
*************** copy_cost (rtx x, enum machine_mode mode
*** 1856,1861 ****
--- 1932,1940 ----
sri.extra_cost = 0;
secondary_class = targetm.secondary_reload (to_p, x, class, mode, &sri);
+ if (!move_cost[mode])
+ init_move_cost (mode);
+
if (secondary_class != NO_REGS)
return (move_cost[mode][(int) secondary_class][(int) class]
+ sri.extra_cost
*************** record_address_regs (enum machine_mode m
*** 2056,2061 ****
--- 2135,2142 ----
pp->mem_cost += (MEMORY_MOVE_COST (Pmode, class, 1) * scale) / 2;
+ if (!move_cost[Pmode])
+ init_move_cost (Pmode);
for (i = 0; i < N_REG_CLASSES; i++)
pp->cost[i] += (may_move_in_cost[Pmode][i][(int) class] * scale) / 2;
}
next prev parent reply other threads:[~2007-07-24 15:01 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-07-24 5:54 Jan Hubicka
2007-07-24 7:29 ` Richard Guenther
2007-07-24 7:52 ` Paolo Bonzini
2007-07-24 15:14 ` Jan Hubicka [this message]
2007-07-29 21:32 ` Rask Ingemann Lambertsen
2007-07-31 6:44 ` Jan Hubicka
2007-07-31 12:49 ` Rask Ingemann Lambertsen
2007-07-31 16:26 ` Jan Hubicka
2007-08-03 9:16 ` Rask Ingemann Lambertsen
2007-08-03 12:13 ` Michael Matz
2007-08-03 12:43 ` Rask Ingemann Lambertsen
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=20070724150127.GE10270@kam.mff.cuni.cz \
--to=jh@suse.cz \
--cc=bonzini@gnu.org \
--cc=gcc-patches@gcc.gnu.org \
--cc=richard.guenther@gmail.com \
/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).