[gnu.gcc.bug] delayed branch

grunwald@FOOBAR.COLORADO.EDU (Dirk Grunwald) (12/13/89)

Do any of the machine descriptions actually use the delayed branch
code? I looked for HAVE_DELAYED_BRANCH in the config directory, but
didn't see anything.

If not, does anyone know if it still works?

meissner@DG-RTP.DG.COM (Michael Meissner) (12/14/89)

>  From: grunwald@FOOBAR.COLORADO.EDU (Dirk Grunwald)
>  Newsgroups: gnu.gcc.bug
>  Date: 13 Dec 89 00:01:07 GMT
>  Reply-To: grunwald@foobar.colorado.edu
>  Distribution: gnu
>  Organization: GNUs Not Usenet
>  
>  
>  Do any of the machine descriptions actually use the delayed branch
>  code? I looked for HAVE_DELAYED_BRANCH in the config directory, but
>  didn't see anything.
>  
>  If not, does anyone know if it still works?

I have started using it with the 88k stuff (which is not yet merged
with the FSF sources).  After fixing the major bug, and the two minor
ones, it seems to work well, and allowed me to remove some 10
peepholes, which we were using to fill delay slots before.  The bugs
that I remember are:

    1)	The delayed branch code would sometimes move a store, after a
	load, which causes problems if the store and load are to the
	same memory location.  I changed it to consider any store
	which preceedes loads from memory is considered ineligible due
	to aliases, and the optimizer not catching all redunant loads,
	it is better to be safe and a little slower, than fast and
	produce the wrong answer.  The case (from genrecog.c) that
	produced this check was: 

		p->pi = q->pi;
		if (*p->pi == 0)
			p->pi = 0;

    2)	The file dbranch.c is not included in the list of objects
	comprising the compiler.  This is fairly trivial to do.

    3)	If you build dbranch.c for a target which does not have
	delayed branching, you will get undefined errors.  I fixed
	this by enclosing everything after the include files with an
	appropriate #ifdef.

Note, if you want to reply to me personally, you probably should use
the email address:  meissner@osf.org.  If you want to talk about 88k
specific stuff, you probably should use:  wood@dg-rtp.dg.com.  We have
put a revmarked version of our changes to 1.36 on our anonymous FTP
server (dg-rtp.dg.com), as Tom has mentioned in an other article.
This version does include direct support for delayed branching.

Here are the patches for fixing the delayed branch code:

*** dbranch.c.orig	Thu Oct 26 11:17:52 1989
--- dbranch.c	Thu Oct 26 13:10:20 1989
***************
*** 99,104 ****
--- 99,106 ----
  
  FILE *dbr_dump_file;
  
+ #ifdef HAVE_DELAYED_BRANCH
+ 
  /* The number of unfilled delay slots in the current sequence. */
  static int slots_avail;
  
***************
*** 107,112 ****
--- 109,119 ----
  
  static int memw;
  
+ /* A flag, nonzero indicating that some insn that could not 
+    go in a slot reads from memory.  */
+ 
+ static int memr;
+ 
  /* A flag, nonzero indicating that the condition code is written 
     by some insn that couldn't go in a delay slot.  */
  
***************
*** 175,181 ****
  init_flags ()
  {
    CLEAR_HARD_REG_SET (regw);
!   memw = ccw = 0;
    note_stores (PATTERN (dinsn), pnote);
    if (LOG_LINKS (dinsn))
      dep_insn_list = copy_rtx (LOG_LINKS (dinsn));
--- 182,188 ----
  init_flags ()
  {
    CLEAR_HARD_REG_SET (regw);
!   memw = memr = ccw = 0;
    note_stores (PATTERN (dinsn), pnote);
    if (LOG_LINKS (dinsn))
      dep_insn_list = copy_rtx (LOG_LINKS (dinsn));
***************
*** 188,213 ****
  /* Called through note_stores on possibly eligible insn patterns.
     Checks to see if a register written by the pattern is needed by an already
     ineligible insn.  Sets the global EFLAG nonzero if a dependency
!    is found.  */
  
  static void 
! enote (x, p)
!      rtx x;
       rtx p;
  {
    if (eflag == 0)
      {
!       if (GET_CODE (x) == REG)
  	{
! 	  if (reg_used_between_p (x, insn, dinsn))
  	    goto lose;
! 	  if ((!FUNCTION_VALUE_REGNO_P (REGNO (x)) || 
  	       GET_CODE (dinsn) != CALL_INSN) &&
! 	      reg_mentioned_p (x, (PATTERN (dinsn))))
  	    goto lose;
  	}
!       else if (x == cc0_rtx && 
! 	       reg_used_between_p (x, insn, NEXT_INSN (dinsn)))
  	goto lose;
        return;
      lose:
--- 195,244 ----
  /* Called through note_stores on possibly eligible insn patterns.
     Checks to see if a register written by the pattern is needed by an already
     ineligible insn.  Sets the global EFLAG nonzero if a dependency
!    is found.
! 
!    Any store which preceedes loads from memory is considered ineligible due
!    to aliases, and the optimizer not catching all redunant loads, it is
!    better to be safe and a little slower, than fast and produce the wrong
!    answer.  The case (from genrecog.c) that produced this check was:
! 
! 	p->pi = q->pi;
! 	if (*p->pi == 0)
! 		p->pi = 0;	*/
  
  static void 
! enote (dest, p)
!      rtx dest;
       rtx p;
  {
+   rtx src = SET_SRC (p);
+   while (GET_CODE (src) == SUBREG
+ 	 || GET_CODE (src) == ZERO_EXTRACT
+ 	 || GET_CODE (src) == SIGN_EXTRACT
+ 	 || GET_CODE (src) == STRICT_LOW_PART)
+     src = XEXP (src, 0);
+ 
+   if (GET_CODE (src) == MEM)
+     memr = TRUE;
+ 
+   if (GET_CODE (dest) == MEM)
+     memw = TRUE;
+ 
    if (eflag == 0)
      {
!       if (GET_CODE (dest) == MEM && memr)
! 	goto lose;
!       else if (GET_CODE (dest) == REG)
  	{
! 	  if (reg_used_between_p (dest, insn, dinsn))
  	    goto lose;
! 	  if ((!FUNCTION_VALUE_REGNO_P (REGNO (dest)) || 
  	       GET_CODE (dinsn) != CALL_INSN) &&
! 	      reg_mentioned_p (dest, (PATTERN (dinsn))))
  	    goto lose;
  	}
!       else if (dest == cc0_rtx && 
! 	       reg_used_between_p (dest, insn, NEXT_INSN (dinsn)))
  	goto lose;
        return;
      lose:
***************
*** 233,239 ****
       - is in the dependency list of an ineligible insn.
       - writes a hard register needed by an ineligible insn.
       - reads a register written by an ineligible insn.
!      - refers to memory.
       - sets the condition code.    
       - violates a machine-dependent constraint.  */
  
--- 264,270 ----
       - is in the dependency list of an ineligible insn.
       - writes a hard register needed by an ineligible insn.
       - reads a register written by an ineligible insn.
!      - refers to volatile memory.
       - sets the condition code.    
       - violates a machine-dependent constraint.  */
  
***************
*** 244,253 ****
    rtx pat = PATTERN (insn);
    int i,s;
  
-   /* See if there are any explicit dependencies on this insn. */
-   if (in_dep_list_p (insn))
-     return 0;
-   
    /* Check for implicit dependencies by calling enote on each
       store rtx.  ENOTE makes sure that no ineligible instruction
       refers to a register in a way that flow analysis 
--- 275,280 ----
***************
*** 257,269 ****
    if (eflag)
      return 0;
  
!   /* Check for volatile memory refs if any already ineligible. */
! 
!   if (memw && volatile_refs_p (pat))
!     {
!       memw = TRUE;
!       return 0;
!     }
  
    /* See if it refers to any regs that are clobbered by ineligibles. */
  
--- 284,297 ----
    if (eflag)
      return 0;
  
!   /* See if there are any explicit dependencies on this insn. */
!   if (in_dep_list_p (insn))
!     return 0;
!   
!   /* Check for volatile memory refs if any other memory ref has
!      been made.  */
!   if ((memw | memr) && volatile_refs_p (pat))
!     return 0;
  
    /* See if it refers to any regs that are clobbered by ineligibles. */
  
***************
*** 447,449 ****
--- 475,479 ----
  	  first = NEXT_INSN (insn);	    
      }
  }
+ 
+ #endif /* ifdef HAVE_DELAYED_BRANCH */

--
Michael Meissner, Data General.
Until 12/15:	meissner@dg-rtp.DG.COM
After 12/15:	meissner@osf.org