public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Bernd Schmidt <bernds_cb1@t-online.de>
To: GCC Patches <gcc-patches@gcc.gnu.org>
Subject: regrename speedup
Date: Sat, 17 Oct 2009 14:46:00 -0000	[thread overview]
Message-ID: <4AD9CEF2.50908@t-online.de> (raw)

[-- Attachment #1: Type: text/plain, Size: 982 bytes --]

PR38582 has a testcase which spends a lot of time in the register
renamer.  One problem here is quite obvious: we always scan a whole
chain to find its end so that we can insert a new element.  The patch
below fixes this by rearranging the data structures a little.

The testcase still consumes a lot of time in the renamer, but the
problem is shifted to merge_overlapping_regs which probably needs rewriting.

Bootstrapped & regression tested on i686-linux (failures match those
seen in gcc-testresults), which is however meaningless as
-frename-registers isn't tested.  I've compiled a large number of files
both with and without this patch with -frename-registers, and output was
identical in all cases.

OK?


Bernd
-- 
This footer brought to you by insane German lawmakers.
Analog Devices GmbH      Wilhelm-Wagenfeld-Str. 6      80807 Muenchen
Sitz der Gesellschaft Muenchen, Registergericht Muenchen HRB 40368
Geschaeftsfuehrer Thomas Wessel, William A. Martin, Margaret Seif

[-- Attachment #2: rr-speed.diff --]
[-- Type: text/plain, Size: 14117 bytes --]


	PR rtl/38582
	* regrename.c (struct du_head): New structure; some elements moved
	from...
	(struct du_chain): ... this one.
	(open_chains, closed_chains): Now of type struct du_head *.
	(do_replace): Accept du_head argument, not du_chain.  All callers
	changed.  Modified code to match new data structures.
	(build_def_use): Return a list of du_head structures.  Modified code
	to match new data structures.
	(dump_def_use_chain): Accept du_head argument, not du_chain.  All
	callers changed.  Modified code to match new data structures.
	(merge_overlapping_regs): Accept du_head argument, not du_chain.  All
	callers changed.  Modified code to match new data structures.
	(scan_rtx_reg): Change type of this_regno and this_nregs to unsigned.
	Allocate a du_head structure as well as a du_chain when creating a
	new chain.  Modified other code to match new data structures.

Index: regrename.c
===================================================================
--- regrename.c	(revision 152847)
+++ regrename.c	(working copy)
@@ -40,15 +40,35 @@
 #include "tree-pass.h"
 #include "df.h"
 
+/* We keep linked lists of DU_HEAD structures, each of which describes
+   a chain of occurrences of a reg.  */
+struct du_head
+{
+  /* The next chain.  */
+  struct du_head *next_chain;
+  /* The first and last elements of this chain.  */
+  struct du_chain *first, *last;
+  /* Describes the register being tracked.  */
+  unsigned regno, nregs;
+  /* Nonzero if the chain crosses a call.  */
+  unsigned int need_caller_save_reg:1;
+  /* Nonzero if the chain is finished.  */
+  unsigned int terminated:1;
+};
+
+/* This struct describes a single occurrence of a register.  */
 struct du_chain
 {
-  struct du_chain *next_chain;
+  /* Links to the next occurrence of the register.  */
   struct du_chain *next_use;
 
+  /* The insn where the register appears.  */
   rtx insn;
+  /* The location inside the insn.  */
   rtx *loc;
+  /* The register class required by the insn at this location.  */
   ENUM_BITFIELD(reg_class) cl : 16;
-  unsigned int need_caller_save_reg:1;
+  /* Nonzero if the register is subject to earlyclobber.  */
   unsigned int earlyclobber:1;
 };
 
@@ -79,19 +99,19 @@ static const char * const scan_actions_n
 
 static struct obstack rename_obstack;
 
-static void do_replace (struct du_chain *, int);
+static void do_replace (struct du_head *, int);
 static void scan_rtx_reg (rtx, rtx *, enum reg_class,
 			  enum scan_actions, enum op_type, int);
 static void scan_rtx_address (rtx, rtx *, enum reg_class,
 			      enum scan_actions, enum machine_mode);
 static void scan_rtx (rtx, rtx *, enum reg_class, enum scan_actions,
 		      enum op_type, int);
-static struct du_chain *build_def_use (basic_block);
-static void dump_def_use_chain (struct du_chain *);
+static struct du_head *build_def_use (basic_block);
+static void dump_def_use_chain (struct du_head *);
 static void note_sets (rtx, const_rtx, void *);
 static void clear_dead_regs (HARD_REG_SET *, enum reg_note, rtx);
 static void merge_overlapping_regs (basic_block, HARD_REG_SET *,
-				    struct du_chain *);
+				    struct du_head *);
 
 /* Called through note_stores.  Find sets of registers, and
    record them in *DATA (which is actually a HARD_REG_SET *).  */
@@ -127,14 +147,14 @@ clear_dead_regs (HARD_REG_SET *pset, enu
       }
 }
 
-/* For a def-use chain CHAIN in basic block B, find which registers overlap
+/* For a def-use chain HEAD in basic block B, find which registers overlap
    its lifetime and set the corresponding bits in *PSET.  */
 
 static void
 merge_overlapping_regs (basic_block b, HARD_REG_SET *pset,
-			struct du_chain *chain)
+			struct du_head *head)
 {
-  struct du_chain *t = chain;
+  struct du_chain *t;
   rtx insn;
   HARD_REG_SET live;
   df_ref *def_rec;
@@ -146,6 +166,8 @@ merge_overlapping_regs (basic_block b, H
       if (DF_REF_FLAGS (def) & DF_REF_AT_TOP)
 	SET_HARD_REG_BIT (live, DF_REF_REGNO (def));
     }
+
+  t = head->first;
   insn = BB_HEAD (b);
   while (t)
     {
@@ -159,7 +181,7 @@ merge_overlapping_regs (basic_block b, H
 	      note_stores (PATTERN (insn), note_sets, (void *) &live);
 	      /* Only record currently live regs if we are inside the
 		 reg's live range.  */
-	      if (t != chain)
+	      if (t != head->first)
 		IOR_HARD_REG_SET (*pset, live);
 	      clear_dead_regs (&live, REG_UNUSED, REG_NOTES (insn));
 	    }
@@ -200,7 +222,7 @@ regrename_optimize (void)
 
   FOR_EACH_BB (bb)
     {
-      struct du_chain *all_chains = 0;
+      struct du_head *all_chains = 0;
       HARD_REG_SET unavailable;
       HARD_REG_SET regs_seen;
 
@@ -229,13 +251,13 @@ regrename_optimize (void)
 	{
 	  int new_reg, best_new_reg;
 	  int n_uses;
-	  struct du_chain *this_du = all_chains;
+	  struct du_head *this_head = all_chains;
 	  struct du_chain *tmp;
 	  HARD_REG_SET this_unavailable;
-	  int reg = REGNO (*this_du->loc);
+	  int reg = this_head->regno;
 	  int i;
 
-	  all_chains = this_du->next_chain;
+	  all_chains = this_head->next_chain;
 
 	  best_new_reg = reg;
 
@@ -262,7 +284,7 @@ regrename_optimize (void)
 	  /* Count number of uses, and narrow the set of registers we can
 	     use for renaming.  */
 	  n_uses = 0;
-	  for (tmp = this_du; tmp; tmp = tmp->next_use)
+	  for (tmp = this_head->first; tmp; tmp = tmp->next_use)
 	    {
 	      if (DEBUG_INSN_P (tmp->insn))
 		continue;
@@ -274,16 +296,17 @@ regrename_optimize (void)
 	  if (n_uses < 2)
 	    continue;
 
-	  if (this_du->need_caller_save_reg)
+	  if (this_head->need_caller_save_reg)
 	    IOR_HARD_REG_SET (this_unavailable, call_used_reg_set);
 
-	  merge_overlapping_regs (bb, &this_unavailable, this_du);
+	  merge_overlapping_regs (bb, &this_unavailable, this_head);
 
 	  /* Now potential_regs is a reasonable approximation, let's
 	     have a closer look at each register still in there.  */
 	  for (new_reg = 0; new_reg < FIRST_PSEUDO_REGISTER; new_reg++)
 	    {
-	      int nregs = hard_regno_nregs[new_reg][GET_MODE (*this_du->loc)];
+	      enum machine_mode mode = GET_MODE (*this_head->first->loc);
+	      int nregs = hard_regno_nregs[new_reg][mode];
 
 	      for (i = nregs - 1; i >= 0; --i)
 	        if (TEST_HARD_REG_BIT (this_unavailable, new_reg + i)
@@ -308,10 +331,10 @@ regrename_optimize (void)
 
 	      /* See whether it accepts all modes that occur in
 		 definition and uses.  */
-	      for (tmp = this_du; tmp; tmp = tmp->next_use)
+	      for (tmp = this_head->first; tmp; tmp = tmp->next_use)
 		if ((! HARD_REGNO_MODE_OK (new_reg, GET_MODE (*tmp->loc))
 		     && ! DEBUG_INSN_P (tmp->insn))
-		    || (tmp->need_caller_save_reg
+		    || (this_head->need_caller_save_reg
 			&& ! (HARD_REGNO_CALL_PART_CLOBBERED
 			      (reg, GET_MODE (*tmp->loc)))
 			&& (HARD_REGNO_CALL_PART_CLOBBERED
@@ -327,8 +350,8 @@ regrename_optimize (void)
 	  if (dump_file)
 	    {
 	      fprintf (dump_file, "Register %s in insn %d",
-		       reg_names[reg], INSN_UID (this_du->insn));
-	      if (this_du->need_caller_save_reg)
+		       reg_names[reg], INSN_UID (this_head->first->insn));
+	      if (this_head->need_caller_save_reg)
 		fprintf (dump_file, " crosses a call");
 	    }
 
@@ -343,7 +366,7 @@ regrename_optimize (void)
 	  if (dump_file)
 	    fprintf (dump_file, ", renamed as %s\n", reg_names[best_new_reg]);
 
-	  do_replace (this_du, best_new_reg);
+	  do_replace (this_head, best_new_reg);
 	  tick[best_new_reg] = ++this_tick;
 	  df_set_regs_ever_live (best_new_reg, true);
 	}
@@ -360,16 +383,17 @@ regrename_optimize (void)
 }
 
 static void
-do_replace (struct du_chain *chain, int reg)
+do_replace (struct du_head *head, int reg)
 {
-  unsigned int base_regno = REGNO (*chain->loc);
+  struct du_chain *chain;
+  unsigned int base_regno = head->regno;
 
-  gcc_assert (! DEBUG_INSN_P (chain->insn));
+  gcc_assert (! DEBUG_INSN_P (head->first->insn));
 
-  while (chain)
+  for (chain = head->first; chain; chain = chain->next_use)
     {
       unsigned int regno = ORIGINAL_REGNO (*chain->loc);
-      struct reg_attrs * attr = REG_ATTRS (*chain->loc);
+      struct reg_attrs *attr = REG_ATTRS (*chain->loc);
       int reg_ptr = REG_POINTER (*chain->loc);
 
       if (DEBUG_INSN_P (chain->insn) && REGNO (*chain->loc) != base_regno)
@@ -399,37 +423,42 @@ do_replace (struct du_chain *chain, int 
 	}
 
       df_insn_rescan (chain->insn);
-      chain = chain->next_use;
     }
 }
 
 
-static struct du_chain *open_chains;
-static struct du_chain *closed_chains;
+static struct du_head *open_chains;
+static struct du_head *closed_chains;
 
 static void
 scan_rtx_reg (rtx insn, rtx *loc, enum reg_class cl,
 	      enum scan_actions action, enum op_type type, int earlyclobber)
 {
-  struct du_chain **p;
+  struct du_head **p;
   rtx x = *loc;
   enum machine_mode mode = GET_MODE (x);
-  int this_regno = REGNO (x);
-  int this_nregs = hard_regno_nregs[this_regno][mode];
+  unsigned this_regno = REGNO (x);
+  unsigned this_nregs = hard_regno_nregs[this_regno][mode];
 
   if (action == mark_write)
     {
       if (type == OP_OUT)
 	{
+	  struct du_head *head = XOBNEW (&rename_obstack, struct du_head);
 	  struct du_chain *this_du = XOBNEW (&rename_obstack, struct du_chain);
+	  head->next_chain = open_chains;
+	  open_chains = head;
+	  head->first = head->last = this_du;
+	  head->regno = this_regno;
+	  head->nregs = this_nregs;
+	  head->need_caller_save_reg = 0;
+	  head->terminated = 0;
+
 	  this_du->next_use = 0;
-	  this_du->next_chain = open_chains;
 	  this_du->loc = loc;
 	  this_du->insn = insn;
 	  this_du->cl = cl;
-	  this_du->need_caller_save_reg = 0;
 	  this_du->earlyclobber = earlyclobber;
-	  open_chains = this_du;
 	}
       return;
     }
@@ -439,8 +468,8 @@ scan_rtx_reg (rtx insn, rtx *loc, enum r
 
   for (p = &open_chains; *p;)
     {
-      struct du_chain *this_du = *p;
-
+      struct du_head *head = *p;
+      
       /* Check if the chain has been terminated if it has then skip to
 	 the next chain.
 
@@ -448,18 +477,17 @@ scan_rtx_reg (rtx insn, rtx *loc, enum r
 	 the chain in Step 3, but are trying to hide in-out operands
 	 from terminate_write in Step 5.  */
 
-      if (*this_du->loc == cc0_rtx)
-	p = &this_du->next_chain;
+      if (head->terminated)
+	p = &head->next_chain;
       else
 	{
-	  int regno = REGNO (*this_du->loc);
-	  int nregs = hard_regno_nregs[regno][GET_MODE (*this_du->loc)];
-	  int exact_match = (regno == this_regno && nregs == this_nregs);
+	  int exact_match = (head->regno == this_regno
+			     && head->nregs == this_nregs);
 
-	  if (regno + nregs <= this_regno
-	      || this_regno + this_nregs <= regno)
+	  if (head->regno + head->nregs <= this_regno
+	      || this_regno + this_nregs <= head->regno)
 	    {
-	      p = &this_du->next_chain;
+	      p = &head->next_chain;
 	      continue;
 	    }
 
@@ -473,37 +501,36 @@ scan_rtx_reg (rtx insn, rtx *loc, enum r
 		 be replaced with, terminate the chain.  */
 	      if (cl != NO_REGS)
 		{
+		  struct du_chain *this_du;
 		  this_du = XOBNEW (&rename_obstack, struct du_chain);
 		  this_du->next_use = 0;
-		  this_du->next_chain = (*p)->next_chain;
 		  this_du->loc = loc;
 		  this_du->insn = insn;
 		  this_du->cl = cl;
-		  this_du->need_caller_save_reg = 0;
-		  while (*p)
-		    p = &(*p)->next_use;
-		  *p = this_du;
+		  head->last->next_use = this_du;
+		  head->last = this_du;
 		  return;
 		}
 	    }
 
 	  if (action != terminate_overlapping_read || ! exact_match)
 	    {
-	      struct du_chain *next = this_du->next_chain;
+	      struct du_head *next = head->next_chain;
 
 	      /* Whether the terminated chain can be used for renaming
 	         depends on the action and this being an exact match.
 	         In either case, we remove this element from open_chains.  */
 
+	      head->terminated = 1;
 	      if ((action == terminate_dead || action == terminate_write)
 		  && exact_match)
 		{
-		  this_du->next_chain = closed_chains;
-		  closed_chains = this_du;
+		  head->next_chain = closed_chains;
+		  closed_chains = head;
 		  if (dump_file)
 		    fprintf (dump_file,
 			     "Closing chain %s at insn %d (%s)\n",
-			     reg_names[REGNO (*this_du->loc)], INSN_UID (insn),
+			     reg_names[head->regno], INSN_UID (insn),
 			     scan_actions_name[(int) action]);
 		}
 	      else
@@ -511,13 +538,13 @@ scan_rtx_reg (rtx insn, rtx *loc, enum r
 		  if (dump_file)
 		    fprintf (dump_file,
 			     "Discarding chain %s at insn %d (%s)\n",
-			     reg_names[REGNO (*this_du->loc)], INSN_UID (insn),
+			     reg_names[head->regno], INSN_UID (insn),
 			     scan_actions_name[(int) action]);
 		}
 	      *p = next;
 	    }
 	  else
-	    p = &this_du->next_chain;
+	    p = &head->next_chain;
 	}
     }
 }
@@ -760,7 +787,7 @@ scan_rtx (rtx insn, rtx *loc, enum reg_c
 
 /* Build def/use chain.  */
 
-static struct du_chain *
+static struct du_head *
 build_def_use (basic_block bb)
 {
   rtx insn;
@@ -914,7 +941,7 @@ build_def_use (basic_block bb)
 	     requires a caller-saved reg.  */
 	  if (CALL_P (insn))
 	    {
-	      struct du_chain *p;
+	      struct du_head *p;
 	      for (p = open_chains; p; p = p->next_chain)
 		p->need_caller_save_reg = 1;
 	    }
@@ -1014,14 +1041,13 @@ build_def_use (basic_block bb)
    printed in reverse order as that's how we build them.  */
 
 static void
-dump_def_use_chain (struct du_chain *chains)
+dump_def_use_chain (struct du_head *head)
 {
-  while (chains)
+  while (head)
     {
-      struct du_chain *this_du = chains;
-      int r = REGNO (*this_du->loc);
-      int nregs = hard_regno_nregs[r][GET_MODE (*this_du->loc)];
-      fprintf (dump_file, "Register %s (%d):", reg_names[r], nregs);
+      struct du_chain *this_du = head->first;
+      fprintf (dump_file, "Register %s (%d):",
+	       reg_names[head->regno], head->nregs);
       while (this_du)
 	{
 	  fprintf (dump_file, " %d [%s]", INSN_UID (this_du->insn),
@@ -1029,7 +1055,7 @@ dump_def_use_chain (struct du_chain *cha
 	  this_du = this_du->next_use;
 	}
       fprintf (dump_file, "\n");
-      chains = chains->next_chain;
+      head = head->next_chain;
     }
 }
 

             reply	other threads:[~2009-10-17 14:43 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-10-17 14:46 Bernd Schmidt [this message]
2009-10-22 13:09 ` Eric Botcazou
2009-11-12 18:31   ` Bernd Schmidt
2009-11-28  1:39     ` H.J. Lu
2009-11-28  8:55       ` Eric Botcazou
2009-11-30 11:55         ` Bernd Schmidt
2009-11-30 12:19           ` Eric Botcazou
2009-11-30 13:27             ` Bernd Schmidt
2009-12-02 13:13       ` Bernd Schmidt
2009-12-02 18:22         ` Eric Botcazou
2009-12-03 13:08           ` Bernd Schmidt
2009-11-12 18:32 ` Bernd Schmidt
2009-11-19 19:28   ` Eric Botcazou
2009-11-20  1:36     ` Bernd Schmidt
2009-11-20  7:58       ` Eric Botcazou
2009-11-20 21:31         ` Bernd Schmidt
2009-11-22 22:26           ` Eric Botcazou
2009-11-24 11:55             ` Bernd Schmidt
2009-11-24 12:30               ` Eric Botcazou
2009-11-26 12:27               ` Eric Botcazou
2009-11-26 16:50                 ` Bernd Schmidt
2009-11-26 17:46                   ` Eric Botcazou
2009-11-26 23:19                     ` Bernd Schmidt

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=4AD9CEF2.50908@t-online.de \
    --to=bernds_cb1@t-online.de \
    --cc=gcc-patches@gcc.gnu.org \
    /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).