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]

loop bug fix for ia64 tcl miscompilation


With the IA-64 port, make check fails if I compile dejagnu with a current
gcc, because tcl/generic/tclCompExpr.c gets miscompiled.  The miscompilation
happens in the last loop in CompileLorExpr.   I haven't managed to create
a simple testcase that reproduces all of the conditions necessary to
trigger the bug.

The RTL before loop looks like
       loop:
	(set (reg 345) (plus (reg 349) (const_int -1)))
	...
	use of 345
	...
	(set (reg 349) (reg 345))
	compare and branch on reg 349
reg 349 is recognized as a biv decremented by one each loop iteration,
and is not replacable.  reg 345 is a giv with an add_val of -1.  It gets
marked replaceable by check_final_value because it is dead after the loop.
The RTL after loop then looks like
	(set (reg 619) (minus (reg 349) (const_int -1)))
       loop:
	...
	use of reg 619
	...
	(set (reg 619) (plus (reg 619) (const_int -1)))
	(set (reg 349) (reg 619))
	compare and branch on reg 349
The code is now wrong because reg 349 is one too small when used in the
compare.  We can make this work if we put the decrement of reg 619 after the
copy to reg 349, but that only works if no other part of loop does anything
with the insn that sets the biv, which is a risky assumption.  This will
conflict with the auto_inc_dec optimization.  It may conflict with other
optimizations.

It makes more sense to be to notice that the code in record_giv that sets
replaceable uses a <= test to compare the giv lifetime against the biv
lifetime.  Thus if the biv set uses the giv, then the giv is not marked
replaceable.  check_final_value should use the same test.  Viewed this
way, check_final_value has an obvious bug, because it does not handle the
case where the biv and giv are referenced in the same instruction.  It also
fails to set last_giv_use to the last giv use.  The following patch fixes this,
and solves the tclCompExpr.c miscompilation problem.

Tested with an ia32-linux bootstrap and testsuite run, and an ia64 toolchain
build.

2000-09-01  Jim Wilson  <wilson@cygnus.com>

	* loop.c (check_final_value): Check for biv use before checking for
	giv use.  Check for both biv and giv uses.  Always set last_giv_use
	if there is a giv use.

Index: loop.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/loop.c,v
retrieving revision 1.277
diff -p -r1.277 loop.c
*** loop.c	2000/08/29 19:15:26	1.277
--- loop.c	2000/09/01 21:53:40
*************** check_final_value (loop, v)
*** 5677,5695 ****
  	  if (GET_CODE (p) == INSN || GET_CODE (p) == JUMP_INSN
  	      || GET_CODE (p) == CALL_INSN)
  	    {
! 	      if (biv_increment_seen)
  		{
! 		  if (reg_mentioned_p (v->dest_reg, PATTERN (p)))
  		    {
  		      v->replaceable = 0;
  		      v->not_replaceable = 1;
  		      break;
  		    }
  		}
- 	      else if (reg_set_p (v->src_reg, PATTERN (p)))
- 		biv_increment_seen = 1;
- 	      else if (reg_mentioned_p (v->dest_reg, PATTERN (p)))
- 		last_giv_use = p;
  	    }
  	}
  
--- 5677,5701 ----
  	  if (GET_CODE (p) == INSN || GET_CODE (p) == JUMP_INSN
  	      || GET_CODE (p) == CALL_INSN)
  	    {
! 	      /* It is possible for the BIV increment to use the GIV if we
! 		 have a cycle.  Thus we must be sure to check each insn for
! 		 both BIV and GIV uses, and we must check for BIV uses
! 		 first.  */
! 
! 	      if (! biv_increment_seen
! 		  && reg_set_p (v->src_reg, PATTERN (p)))
! 		biv_increment_seen = 1;
! 		
! 	      if (reg_mentioned_p (v->dest_reg, PATTERN (p)))
  		{
! 		  if (biv_increment_seen)
  		    {
  		      v->replaceable = 0;
  		      v->not_replaceable = 1;
  		      break;
  		    }
+ 		  last_giv_use = p;
  		}
  	    }
  	}
  

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