PATCH for bogus loop optimization

Mark Mitchell mark@markmitchell.com
Tue Sep 29 21:34:00 GMT 1998


Consider the following C code:

  int g()
  {
    int n=1000;
    int i;

    f(n);
    for(i=0; i<1; ++i) {
      f(n);
      n=666;
      &n;
    }
  }

Because n has its address taken, we turn n's REG into a 
MEM (ADDRESSOF (REG)).  Unfortunately, the original REG has
REG_USERVAR_P set, while the new REG (embedded in the ADDRESSOF) does
not.  Since the address of n is not really needed, we remove the 
ADDRESSOF bit after CSE.  That leaves a REG, just as if `n' had not
been addressed, but without REG_USERVAR_P set.  That causes scan_loop
to assume that there is only one set for n, and that it comes before
any use of n, but this is false.  The following patch fixes the bug by
making sure that the REG embedded in the ADDRESSOF has REG_USERVAR_P
set if the original REG does.

Would one of the maintainers care to approve this patch?

-- 
Mark Mitchell 			mark@markmitchell.com
Mark Mitchell Consulting	http://www.markmitchell.com

Tue Sep 29 21:27:17 1998  Mark Mitchell  <mark@markmitchell.com>

	* function.c (gen_mem_addressof): If the address REG is
	REG_USERVAR_P make the new REG be so also.
	* loop.c (scan_loop): Apply DeMorgan's laws and add documentation
	in an attempt to clarify slightly.

Index: function.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/function.c,v
retrieving revision 1.42
diff -c -p -r1.42 function.c
*** function.c	1998/09/20 23:29:08	1.42
--- function.c	1998/09/30 04:08:17
*************** gen_mem_addressof (reg, decl)
*** 2756,2764 ****
       tree decl;
  {
    tree type = TREE_TYPE (decl);
- 
    rtx r = gen_rtx_ADDRESSOF (Pmode, gen_reg_rtx (GET_MODE (reg)), REGNO (reg));
    SET_ADDRESSOF_DECL (r, decl);
  
    XEXP (reg, 0) = r;
    PUT_CODE (reg, MEM);
--- 2756,2766 ----
       tree decl;
  {
    tree type = TREE_TYPE (decl);
    rtx r = gen_rtx_ADDRESSOF (Pmode, gen_reg_rtx (GET_MODE (reg)), REGNO (reg));
    SET_ADDRESSOF_DECL (r, decl);
+   /* If the original REG was a user-variable, then so is the REG whose
+      address is being taken.  */
+   REG_USERVAR_P (XEXP (r, 0)) = REG_USERVAR_P (reg);
  
    XEXP (reg, 0) = r;
    PUT_CODE (reg, MEM);
Index: loop.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/loop.c,v
retrieving revision 1.77
diff -c -p -r1.77 loop.c
*** loop.c	1998/09/18 20:54:55	1.77
--- loop.c	1998/09/30 04:08:46
*************** scan_loop (loop_start, end, unroll_p, bc
*** 871,889 ****
  	     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:
! 	     (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,
! 	         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))
  		   && (dependencies == 0
--- 871,901 ----
  	     We don't know its life-span, so we can't compute the benefit.  */
  	  if (REGNO (SET_DEST (set)) >= max_reg_before_loop)
  	    ;
! 	  else if (/* The set is a user-variable or it is used in
! 		      the exit test (this can cause the variable to be
! 		      used before it is set just like a
! 		      user-variable)...  */
! 		   (REG_USERVAR_P (SET_DEST (set))
! 		    || REG_LOOP_TEST_P (SET_DEST (set)))
! 		   /* And the set is not guaranteed to be executed one
! 		      the loop starts, or the value before the set is
! 		      needed before the set occurs... */
! 		   && (maybe_never
! 		       || loop_reg_used_before_p (set, p, loop_start,
! 						  scan_start, end))
! 		   /* And the register is used in basic blocks other
! 		      than the one where it is set (meaning that
! 		      something after this point in the loop might
! 		      depend on its value before the set).  */
! 		   && !reg_in_basic_block_p (p, SET_DEST (set)))
! 	    /* It is unsafe to move the set.  The fact that these
! 	       three conditions are considered in conjunction means
! 	       that we are assuming various conditions, such as:
! 
! 	         o It's OK to move a set of a variable which was not
! 	           created by the user and is not used in an exit test
! 	           even if that point in the set would not be reached
! 		   during execution of the loop.  */
  	    ;
  	  else if ((tem = invariant_p (src))
  		   && (dependencies == 0
Index: testsuite/gcc.c-torture/execute/980929-1.c
===================================================================
RCS file: 980929-1.c
diff -N 980929-1.c
*** /dev/null	Mon Dec 31 20:00:00 1979
--- 980929-1.c	Tue Sep 29 21:16:20 1998
***************
*** 0 ****
--- 1,21 ----
+ void f(int i)
+ {
+   if (i != 1000)
+     abort ();
+ }
+ 
+ 
+ int main()
+ {
+   int n=1000;
+   int i;
+ 
+   f(n);
+   for(i=0; i<1; ++i) {
+     f(n);
+     n=666;
+     &n;
+   }
+ 
+   exit (0);
+ }



More information about the Gcc-patches mailing list