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]

Fix for 991023-1.c



This is a fun little bug which shows up under the following conditions
(which in combination turn out to be relatively rare).

  1. Target must have a CC register that is subject to optimization
     (like the ppc).

  2. We must have a loop in which the loop body also has a check which
     is the same as the loop termination test.

  3. Ignoring issues #1 & #2 the loop must be reversible.


The loop reversal code has checks to determine if the loop biv is used for
anything other than counting loop iterations.  If the biv is just for iteration
counts, then a number of the tests for loop reversal are unnecessary.

The code to check if the biv is just a counter scans the loop rtl to determine
if the biv is used in any way outside of the loop termination test.  The
insns in the loop termination test are ignored as are instructions which
increment the biv.

So, pretend we have a loop like:

LOOP_START
... 
(insn 19 18 20 (set (reg:CC 84)
        (reg/s:CC 83)) -1 (nil)
    (nil))

(jump_insn 20 19 74 (set (pc)
        (if_then_else (ne (reg:CC 84)
                (const_int 0 [0x0]))
            (label_ref 29)
            (pc))) -1 (nil)
    (nil))

...

LOOP_CONT:

(insn 42 76 69 (set (reg/v:SI 82)
        (plus:SI (reg/v:SI 82)
            (const_int 1 [0x1]))) -1 (nil)
    (nil))

(insn 12 69 97 (set (reg/s:CC 83)
        (compare:CC (reg/v:SI 82)
            (const_int 6 [0x6]))) -1 (nil)
    (nil))

(jump_insn 97 12 48 (parallel[
            (set (pc)
                (if_then_else (ne (reg:SI 99)
                        (const_int 1 [0x1]))
                    (label_ref 91)
                    (pc)))
            (set (reg:SI 99)
                (plus:SI (reg:SI 99)
                    (const_int -1 [0xffffffff])))
            (clobber (scratch:CC))
            (clobber (scratch:SI))
        ] ) -1 (nil)
    (nil))

LOOP_END

Where (reg:SI 82) is the biv and it is not referenced anywhere else in the
loop.

Since the biv is not referenced anywhere but the exit test and the increment
loop believes it is only used for counting.  But clearly the biv used to set
(reg:CC 83) which is used inside the loop as well as in the loop exit test.

This relatively simple change detects cases where the exit test references
the biv and also sets a pseudo which has more than one use in the loop.  In
such cases it clears no_use_except_counting and we no longer incorrectly
reverse the loop.


	* loop.c (note_set_pseudo_multiple_uses_retval): New variable.
	(note_set_pseudo_multiple_uses): New function.
	(check_dbra_loop): Use not_set_pseudo_multiple_uses to determine
	if a pseudo set in the loop exit is used elsewhere.

Index: loop.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/loop.c,v
retrieving revision 1.156.4.7
diff -c -3 -p -r1.156.4.7 loop.c
*** loop.c	1999/06/25 04:38:11	1.156.4.7
--- loop.c	1999/10/25 06:40:35
*************** static struct movable *the_movables;
*** 283,288 ****
--- 283,291 ----
  
  FILE *loop_dump_stream;
  
+ /* For communicating return values from note_set_pseudo_multiple_uses.  */
+ static int note_set_pseudo_multiple_uses_retval;
+ 
  /* Forward declarations.  */
  
  static void verify_dominator PROTO((int));
*************** static void count_one_set PROTO((rtx, rt
*** 297,302 ****
--- 300,306 ----
  static void count_loop_regs_set PROTO((rtx, rtx, varray_type, varray_type,
  				       int *, int)); 
  static void note_addr_stored PROTO((rtx, rtx));
+ static void note_set_pseudo_multiple_uses PROTO((rtx, rtx));
  static int loop_reg_used_before_p PROTO((rtx, rtx, rtx, rtx, rtx));
  static void scan_loop PROTO((rtx, rtx, rtx, int, int));
  #if 0
*************** note_addr_stored (x, y)
*** 3140,3145 ****
--- 3144,3179 ----
  
    loop_store_mems = gen_rtx_EXPR_LIST (VOIDmode, x, loop_store_mems);
  }
+ 
+ /* X is a value modified by an INSN that references a biv inside a loop
+    exit test (ie, X is somehow related to the value of the biv).  If X
+    is a pseudo that is used more than once, then the biv is (effectively)
+    used more than once.  */
+ 
+ static void
+ note_set_pseudo_multiple_uses (x, y)
+      rtx x;
+      rtx y ATTRIBUTE_UNUSED;
+ {
+   if (x == 0)
+     return;
+ 
+   while (GET_CODE (x) == STRICT_LOW_PART
+ 	 || GET_CODE (x) == SIGN_EXTRACT
+ 	 || GET_CODE (x) == ZERO_EXTRACT
+ 	 || GET_CODE (x) == SUBREG)
+     x = XEXP (x, 0);
+ 
+   if (GET_CODE (x) != REG || REGNO (x) < FIRST_PSEUDO_REGISTER)
+     return;
+ 
+   /* If we do not have usage information, or if we know the register
+      is used more than once, note that fact for check_dbra_loop.  */
+   if (REGNO (x) >= max_reg_before_loop
+       || ! VARRAY_RTX (reg_single_usage, REGNO (x))
+       || VARRAY_RTX (reg_single_usage, REGNO (x)) == const0_rtx)
+     note_set_pseudo_multiple_uses_retval = 1;
+ }
  
  /* Return nonzero if the rtx X is invariant over the current loop.
  
*************** check_dbra_loop (loop_end, insn_count, l
*** 7764,7774 ****
  		if (set && GET_CODE (SET_DEST (set)) == REG
  		    && REGNO (SET_DEST (set)) == bl->regno)
  		  /* An insn that sets the biv is okay.  */
- 		  ;
- 		else if (p == prev_nonnote_insn (prev_nonnote_insn (loop_end))
- 			 || p == prev_nonnote_insn (loop_end))
- 		  /* Don't bother about the end test.  */
  		  ;
  		else if (reg_mentioned_p (bivreg, PATTERN (p)))
  		  {
  		    no_use_except_counting = 0;
--- 7798,7820 ----
  		if (set && GET_CODE (SET_DEST (set)) == REG
  		    && REGNO (SET_DEST (set)) == bl->regno)
  		  /* An insn that sets the biv is okay.  */
  		  ;
+ 		else if ((p == prev_nonnote_insn (prev_nonnote_insn (loop_end))
+ 			  || p == prev_nonnote_insn (loop_end))
+ 			 && reg_mentioned_p (bivreg, PATTERN (p)))
+ 		  {
+ 		    /* If either of these insns uses the biv and sets a pseudo
+ 		       that has more than one usage, then the biv has uses
+ 		       other than counting since it's used to derive a value
+ 		       that is used more than one time.  */
+ 		    note_set_pseudo_multiple_uses_retval = 0;
+ 		    note_stores (PATTERN (p), note_set_pseudo_multiple_uses);
+ 		    if (note_set_pseudo_multiple_uses_retval)
+ 		      {
+ 			no_use_except_counting = 0;
+ 			break;
+ 		      }
+ 		  }
  		else if (reg_mentioned_p (bivreg, PATTERN (p)))
  		  {
  		    no_use_except_counting = 0;


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