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]

REG_USERVAR_P and GCSE



The attached test program, compiled with egcs 1.1b (and my previous
GCSE fix) under powerpc-linux, with 'gcc -O2 x.c -o x', abort()s in
f2, when it should not.

I'll save everyone the long discussion of what GCSE is doing to the
program (although this is a great example of how GCSE works).  The
problem is that GCSE is creating a new register, register 94 when I
run it, which does not have REG_USERVAR_P set:

(insn 106 29 30 (set (reg:CC 94)
        (compare:CC (reg/v:SI 83)
            (const_int 0))) -1 (nil)
    (nil))

[this corresponds to 'nparts', but moved into a CC register]

and setting it in basic blocks 1, 3, and 9. (I don't know why it
doesn't create it in bb 0 instead of bb 1 and 3, it might be
worthwhile adding a little code to fix this).

Then loop.c is assuming that all non-user registers are only used
in a loop after they are set, and this is not true in this case (it's
used in block 5 after being set in block 3).

My patch is attached.  Another possibility is to set REG_USERVAR_P in
GCSE when it creates new registers, in which case I strongly recommend
changing the name to something like REG_LONGLIFE_P.

This patch, or something, should go in egcs 1.1.1 if possible.  I
think the original code is from metamail, but this is now
unrecognisably different.

-- 
Geoffrey Keating <geoffk@ozemail.com.au>

===File /tmp/x.c============================================
extern int f2(void);
extern int f3(void);
extern void f1(void);

void
ff(int fname, int part, int nparts)
{
  if (fname)  /* bb 0 */
    {
      if (nparts)  /* bb 1 */
	f1();  /* bb 2 */
    }
  else
    fname = 2; /* bb 3  */

  /* bb 4 is the branch to bb 10
     (bb 10 is physically at the end of the loop) */
  while (f3() /* bb 10 */)
    {
      if (nparts /* bb 5 */ && f2() /* bb 6 */)
	{
	  f1();  /* bb 7 ... */
	  nparts = part;
	  if (f3())  /* ... bb 7 */
	    f1();  /* bb 8 */
	  f1(); /* bb 9 */
	  break;
	}
    }

  if (nparts)  /* bb 11 */
    f1(); /* bb 12 */
  return; /* bb 13 */
}

int main(void)
{
  ff(0, 1, 0);
  return 0;
}

int f3(void) { static int x = 0; x = !x; return x; }
void f1(void) { abort(); }
int f2(void) { abort(); }
============================================================

===File ~/patches/egcs-7.diff===============================
--- gcc/loop.c~	Sat Aug 15 10:32:19 1998
+++ gcc/loop.c	Sat Oct 17 17:33:20 1998
@@ -786,18 +786,13 @@
 	     We don't know its life-span, so we can't compute the benefit.  */
 	  if (REGNO (SET_DEST (set)) >= max_reg_before_loop)
 	    ;
-	  /* In order to move a register, we need to have one of three cases:
+	  /* In order to move a register, we need to have either:
 	     (1) it is used only in the same basic block as the set
-	     (2) it is not a user variable and it is not used in the
-	         exit test (this can cause the variable to be used
-		 before it is set just like a user-variable).
-	     (3) the set is guaranteed to be executed once the loop starts,
+	     (2) the set is guaranteed to be executed once the loop starts,
 	         and the reg is not used until after that.  */
 	  else if (! ((! maybe_never
 		       && ! loop_reg_used_before_p (set, p, loop_start,
 						    scan_start, end))
-		      || (! REG_USERVAR_P (SET_DEST (set))
-			  && ! REG_LOOP_TEST_P (SET_DEST (set)))
 		      || reg_in_basic_block_p (p, SET_DEST (set))))
 	    ;
 	  else if ((tem = invariant_p (src))
============================================================


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