This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Experimental patch for better floating point code on x86


Hi list,

A few weeks ago there was another patch targetting the same area
http://gcc.gnu.org/ml/gcc-patches/2005-04/msg01866.html

Well, I tried a different approach, it is still experimental and
just thought as a basis for discussion. For the example given in
the attached link, I get the same assembler output as the original
code, but for other snipplets I get better code. So I know there
is something to do.

The general idea behind the changes is, that the x86 fp instructions
always need the top-stack register as one operand. This is true
for all fp statements. Now, each fp instructions also sets the
top-stack register. So, I try to prevent scheduling an insn which
uses a different fp register than the one which was used last, if
at the same time there is one fp instruction which uses the last
one, is ready for scheduling.

If I find such a combination, then I remove the one which uses a
different fp register from the ready queue and push it back to the
common queue. This way I try to prevent fxch statements within a
block.

I know, that there is a need for more sophisticated checks, like a
lookahead in some cases, and I know that I need to check a few more
INSN types, like PARALLEL, if they set an fp register. There is
also a need to examine the edges to prevent more fxch statements
at the beginning/end of a block. But as I said, it should be a
base for discussions.

Thanks
Wolfgang Formann
--- haifa-sched.c.orig	Wed May  4 06:04:32 2005
+++ haifa-sched.c	Mon May  9 09:51:09 2005
@@ -506,6 +506,16 @@
 }
 #else
 
+#ifdef STACK_REGS
+/* holds the stack register modified by the last insn affecting those
+   registers.  This is used to compute the cost of a scheduled insn.
+   Reason: If a loop on x86 contains almost only floating point
+   instructions, then almost every such instructions is followed by some
+   fxch instruction, causing very poor performance.  */
+
+static int last_stack_register = 0;
+#endif
+
 /* Pointer to the last instruction scheduled.  Used by rank_for_schedule,
    so that insns independent of the last scheduled insn will be preferred
    over dependent instructions.  */
@@ -1932,6 +1942,11 @@
 
 	  advance_one_cycle ();
 
+	  if (sched_verbose >= 2)
+	    {
+	      fprintf (sched_dump, ";;\t\tReady list before queue_to_ready:  ");
+	      debug_ready_list (&ready);
+	    }
 	  /* Add to the ready list all pending insns that can be issued now.
 	     If there are no ready insns, increment clock until one
 	     is ready and add all pending insns at that point to the ready
@@ -1950,6 +1965,75 @@
 	}
       while (advance > 0);
 
+#ifdef STACK_REGS
+      /* if I have a remembered stack register and at least 2 insns
+	 to schedule, then check if any of these insns access a
+	 stack register which is _not_ the remembered one.  In this
+	 case push that insn back into the queue.  */
+      if (last_stack_register != 0 && ready.n_ready >= 2)
+	{
+	  rtx *p;
+	  int i;
+	  bool found_mention_current = false;
+
+	  if (sched_verbose >= 2)
+	    fprintf (sched_dump, ";;\t\tReady list mentioning:  ");
+	  /* first loop, just check if the current stack register is
+	     mentioned.  */
+	  p = ready_lastpos (&ready);
+	  for (i = 0; i < ready.n_ready; i++)
+	    {
+	      rtx r_pat = PATTERN (p[i]);
+	      if (reg_mentioned_p (regno_reg_rtx[last_stack_register], r_pat))
+		{
+		  found_mention_current = true;
+		  if (sched_verbose >= 2)
+		    fprintf (sched_dump, "  %s:Y", (*current_sched_info->print_insn) (p[i], 0));
+		  break;
+		}
+	      else
+		{
+		  if (sched_verbose >= 2)
+		    fprintf (sched_dump, "  %s:N", (*current_sched_info->print_insn) (p[i], 0));
+		}
+	    }
+
+	  if (sched_verbose >= 2)
+	    fprintf (sched_dump, "\n");
+
+	  /* did we find a stack register different to the remembered?  */
+	  if (found_mention_current == true)
+	    {
+	      for (i = 0; i < ready.n_ready; i++)
+		{
+		  int j;
+		  rtx r_pat = PATTERN (ready_element (&ready, i));
+		  if (reg_mentioned_p (regno_reg_rtx[last_stack_register], r_pat))
+		    continue;
+		  for (j = FIRST_STACK_REG; j <= LAST_STACK_REG; ++ j)
+		    {
+		      if (j == last_stack_register)
+			continue;
+		      if (reg_mentioned_p (regno_reg_rtx[j], r_pat)) {
+			queue_insn (ready_element (&ready, i), clock_var + 1);
+			if (sched_verbose >= 2)
+			  fprintf (sched_dump, "Remove from Ready (%d) %s\n", i, (*current_sched_info->print_insn) (p[i], 0));
+			ready_remove (&ready, i);
+			-- i;
+			p = ready_lastpos (&ready);
+			if (sched_verbose >= 2)
+			  {
+			    fprintf (sched_dump, ";;\t\tReady list after remove:  ");
+			    debug_ready_list (&ready);
+			  }
+			break;
+		      }
+		    }
+		}
+	    }
+	}
+#endif
+
       if (sort_p)
 	{
 	  /* Sort the ready list based on priority.  */
@@ -2082,6 +2166,34 @@
 
 	  advance = schedule_insn (insn, &ready, clock_var);
 
+#ifdef STACK_REGS
+        {
+	    /* check if the current insn sets a stack register
+	       and remember that in last_stack_register.  */
+            rtx pat = PATTERN (last_scheduled_insn);
+            switch (GET_CODE (pat))
+              {
+              case SET:
+                {
+                  rtx x = XEXP (pat, 0);
+                  if (REGNO (x) >= FIRST_STACK_REG
+                      && REGNO (x) <= LAST_STACK_REG)
+                    {
+                      last_stack_register = REGNO (x);
+		      if (sched_verbose >= 2)
+		      {
+			fprintf (sched_dump, ";;\t\tlast stack reg: ");
+			print_rtl_single(sched_dump, regno_reg_rtx[last_stack_register]);
+		      }
+                    }
+                }
+		break;
+
+	      default:
+              }
+        }
+#endif
+
 	  /* After issuing an asm insn we should start a new cycle.  */
 	  if (advance == 0 && asm_p)
 	    advance = 1;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]