public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* gcse fix
@ 2000-07-03  1:11 Ulf Carlsson
  2000-07-12 13:19 ` Jeffrey A Law
  0 siblings, 1 reply; 7+ messages in thread
From: Ulf Carlsson @ 2000-07-03  1:11 UTC (permalink / raw)
  To: gcc-patches; +Cc: Andreas Jaeger

Hi,

There was a problem with Linux kernel compiles when we used GCC 2.96,
and I have a patch that solves this problem.  The fix is rather
obvious - we verify that the copy register instruction we generate
when optimize really is valid.

I sent the bug report[1] to the gcc-bugs last week.  Keith Wesolowski
has also written a detailed description of the problem:

[Beginning of description by Keith M Wesolowski]

The function of GCSE is to eliminate pieces of code that end up
looking the same. So for example,

	x = y + 4;
	z = y + 4;

ends up looking like
	
	z = y + 4;
	x = z;

Provided that x is not changed between the original two statements, of
course. And this is key: if the compiler thinks the expression hasn't
changed, it will be removed.

In our case, we have

	__asm__("":"=r" (foo)); __asm__("":"=r" (bar));

The rtl corresponding to the two asm sets are:

(insn 14 27 16 (set (reg:QI 83)
        (asm_operands ("") ("=r") 0[ ]
            [ ]  ("foo.c") 7)) -1 (nil)
    (nil))

and

(insn 19 18 21 (set (reg/v:SI 82)
        (asm_operands ("") ("=r") 0[ ]
            [ ]  ("foo.c") 7)) -1 (nil)
    (nil))

Note that both include a 7 in the instruction description - this is
the line number of the inline asm. Since they're on the same line, and
contain the same code and arguments, *** they are the same
instruction. *** The compiler is not smart enough to know that the
instruction operates on operands of two different modes and thus
should be considered different - all it knows is the text inside
__asm__() and the line number.

So the pre_gcse pass removes the first copy of the __asm__ and copies
the value of the output of the last instance of it (word) into the
output register for the first instance of it (byte). Copying an SI (32
bits) into a QI (8 bits) requires a subreg, but the compiler doesn't
generate one. ICE.

Consistent with my explanation, any of the following eliminates the ICE:

	- using __asm__ volatile (...) instead of __asm__ (...)
	- switching the order of dirty (byte) and dirty (word)
	- making sure only one instance of dirty() is ever on a line
	- compiling with -fno-gcse

This is not to say there is no bug; it seems to be that if

	dirty (word); dirty (byte);

is valid and generates valid (even if incorrect - the flip side of
subreg is zero/sign extension) code, then placing them in the opposite
order should do so as well. This requires that gcc be taught to check
the mode of operands in common subexpressions and either a) recognize
them as different if the operands' modes differ, or b) use subreg or
zero/sign extension as appropriate, or c) distinguish among instances
of inline asm even if the instances occur on the same line.

[End of description by Keith M Wesolowski]

We have verified that the patch doesn't break things by boot strapping
the compiler itself on Sparc.  We have also built functional kernels
and glibc with this patch.

Ulf

[1] http://gcc.gnu.org/ml/gcc-bugs/2000-06/msg00646.html

Index: gcse.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/gcse.c,v
retrieving revision 1.89
diff -p -r1.89 gcse.c
*** gcse.c	2000/06/19 01:40:32	1.89
--- gcse.c	2000/07/03 08:09:18
*************** static struct obstack gcse_obstack;
*** 302,308 ****
  /* Non-zero for each mode that supports (set (reg) (reg)).
     This is trivially true for integer and floating point values.
     It may or may not be true for condition codes.  */
! static char can_copy_p[(int) NUM_MACHINE_MODES];
  
  /* Non-zero if can_copy_p has been initialized.  */
  static int can_copy_init_p;
--- 302,308 ----
  /* Non-zero for each mode that supports (set (reg) (reg)).
     This is trivially true for integer and floating point values.
     It may or may not be true for condition codes.  */
! static char can_copy_p[(int) NUM_MACHINE_MODES][(int) NUM_MACHINE_MODES];
  
  /* Non-zero if can_copy_p has been initialized.  */
  static int can_copy_init_p;
*************** gcse_main (f, file)
*** 810,838 ****
  static void
  compute_can_copy ()
  {
!   int i;
! #ifndef AVOID_CCMODE_COPIES
!   rtx reg,insn;
! #endif
    char *free_point = (char *) oballoc (1);
  
!   bzero (can_copy_p, NUM_MACHINE_MODES);
  
    start_sequence ();
    for (i = 0; i < NUM_MACHINE_MODES; i++)
!     if (GET_MODE_CLASS (i) == MODE_CC)
!       {
  #ifdef AVOID_CCMODE_COPIES
! 	can_copy_p[i] = 0;
! #else
! 	reg = gen_rtx_REG ((enum machine_mode) i, LAST_VIRTUAL_REGISTER + 1);
! 	insn = emit_insn (gen_rtx_SET (VOIDmode, reg, reg));
! 	if (recog (PATTERN (insn), insn, NULL_PTR) >= 0)
! 	  can_copy_p[i] = 1;
  #endif
!       }
!     else
!       can_copy_p[i] = 1;
  
    end_sequence ();
  
--- 810,838 ----
  static void
  compute_can_copy ()
  {
!   int i, j;
!   rtx reg1,reg2,insn;
    char *free_point = (char *) oballoc (1);
  
!   bzero (can_copy_p, NUM_MACHINE_MODES * NUM_MACHINE_MODES);
  
    start_sequence ();
    for (i = 0; i < NUM_MACHINE_MODES; i++)
!     for (j = 0; j < NUM_MACHINE_MODES; j++)
  #ifdef AVOID_CCMODE_COPIES
!       if (GET_MODE_CLASS (i) == MODE_CC)
! 	can_copy_p[i][j] = 0;
!       else
  #endif
! 	{
! 	  reg1 = gen_rtx_REG ((enum machine_mode) i,
! 			      LAST_VIRTUAL_REGISTER + 1);
! 	  reg2 = gen_rtx_REG ((enum machine_mode) j,
! 			      LAST_VIRTUAL_REGISTER + 2);
! 	  insn = emit_insn (gen_rtx_SET (VOIDmode, reg1, reg2));
! 	  if (recog (PATTERN (insn), insn, NULL_PTR) >= 0)
! 	    can_copy_p[i][j] = 1;
! 	}
  
    end_sequence ();
  
*************** hash_scan_set (pat, insn, set_p)
*** 1875,1881 ****
        if (! set_p
  	  && regno >= FIRST_PSEUDO_REGISTER
  	  /* Don't GCSE something if we can't do a reg/reg copy.  */
! 	  && can_copy_p [GET_MODE (dest)]
  	  /* Is SET_SRC something we want to gcse?  */
  	  && want_to_gcse_p (src))
  	{
--- 1875,1881 ----
        if (! set_p
  	  && regno >= FIRST_PSEUDO_REGISTER
  	  /* Don't GCSE something if we can't do a reg/reg copy.  */
! 	  && can_copy_p [GET_MODE (dest)][GET_MODE (src)]
  	  /* Is SET_SRC something we want to gcse?  */
  	  && want_to_gcse_p (src))
  	{
*************** hash_scan_set (pat, insn, set_p)
*** 1894,1900 ****
  	       && regno >= FIRST_PSEUDO_REGISTER
  	       && ((GET_CODE (src) == REG
  		    && REGNO (src) >= FIRST_PSEUDO_REGISTER
! 		    && can_copy_p [GET_MODE (dest)])
  		   || GET_CODE (src) == CONST_INT
  		   || GET_CODE (src) == SYMBOL_REF
  		   || GET_CODE (src) == CONST_DOUBLE)
--- 1894,1900 ----
  	       && regno >= FIRST_PSEUDO_REGISTER
  	       && ((GET_CODE (src) == REG
  		    && REGNO (src) >= FIRST_PSEUDO_REGISTER
! 		    && can_copy_p [GET_MODE (dest)][GET_MODE (src)])
  		   || GET_CODE (src) == CONST_INT
  		   || GET_CODE (src) == SYMBOL_REF
  		   || GET_CODE (src) == CONST_DOUBLE)

^ permalink raw reply	[flat|nested] 7+ messages in thread
* gcse fix
@ 2001-11-13 15:03 Jan Hubicka
  2001-11-13 15:03 ` Richard Henderson
  0 siblings, 1 reply; 7+ messages in thread
From: Jan Hubicka @ 2001-11-13 15:03 UTC (permalink / raw)
  To: gcc-patches, gcc-pdo, rth

Hi,
This bug hit me second time.  The problem is that when we create
REG_EQUAL note for insn in the fialed constant propagation, we
do not copy the rtx properly getting rtl sharing problems that can
cause mysterious crashes later.

I;'ve installed it to the branch. OK for mainline?

Fri Nov 16 19:12:08 CET 2001  Jan Hubicka  <jh@suse.cz>

	* gcse.c (try_replace_reg): Copy RTX before creating note.

*** gcse.c.old	Fri Nov 16 16:01:28 2001
--- gcse.c	Fri Nov 16 17:36:26 2001
*************** try_replace_reg (from, to, insn)
*** 3927,3936 ****
      }
  
    /* If we've failed to do replacement, have a single SET, and don't already
!      have a note, add a REG_EQUAL note to not lose information.  */
!   if (!success && note == 0 && set != 0)
!     note = set_unique_reg_note (insn, REG_EQUAL, src);
  
    /* If there is already a NOTE, update the expression in it with our
       replacement.  */
    else if (note != 0)
--- 3927,3938 ----
      }
  
    /* If we've failed to do replacement, have a single SET, and don't already
!      have a note, add a REG_EQUAL note to not lose information.
  
+      The copy is required, as simplify_replace_rtx does not copy the
+      parts that has not been touched.  */
+   if (!success && note == 0 && set != 0)
+     note = set_unique_reg_note (insn, REG_EQUAL, copy_rtx (src));
    /* If there is already a NOTE, update the expression in it with our
       replacement.  */
    else if (note != 0)

^ permalink raw reply	[flat|nested] 7+ messages in thread
* gcse fix
@ 1998-10-19 23:17 Jeffrey A Law
  0 siblings, 0 replies; 7+ messages in thread
From: Jeffrey A Law @ 1998-10-19 23:17 UTC (permalink / raw)
  To: egcs-patches

I've installed this change.  Things like the frame pointer are not clobberd
by a function call :-)


	* gcse.c (compute_hash_table): Correctly identify hard regs which are
	clobbered across calls.
	(compute_rd_kill): Likewise.

Index: gcse.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/./gcc/gcse.c,v
retrieving revision 1.18
diff -c -3 -p -r1.18 gcse.c
*** gcse.c	1998/10/17 12:11:06	1.18
--- gcse.c	1998/10/20 06:15:40
*************** compute_hash_table (f, set_p)
*** 2075,2081 ****
  	  if (GET_CODE (insn) == CALL_INSN)
  	    {
  	      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
! 		if (call_used_regs[regno])
  		  record_last_reg_set_info (insn, regno);
  	      if (! CONST_CALL_P (insn))
  		record_last_mem_set_info (insn);
--- 2075,2094 ----
  	  if (GET_CODE (insn) == CALL_INSN)
  	    {
  	      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
! 		if ((call_used_regs[regno]
! 		     && regno != STACK_POINTER_REGNUM
! #if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
! 		     && regno != HARD_FRAME_POINTER_REGNUM
! #endif
! #if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
! 		     && ! (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
! #endif
! #if defined (PIC_OFFSET_TABLE_REGNUM) && !defined (PIC_OFFSET_TABLE_REG_CALL_CLOBBERED)
! 		     && ! (regno == PIC_OFFSET_TABLE_REGNUM && flag_pic)
! #endif
! 
! 		     && regno != FRAME_POINTER_REGNUM)
! 		    || global_regs[regno])
  		  record_last_reg_set_info (insn, regno);
  	      if (! CONST_CALL_P (insn))
  		record_last_mem_set_info (insn);
*************** compute_kill_rd ()
*** 2548,2554 ****
  
  		  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
                      {
! 		      if (call_used_regs[regno])
  			handle_rd_kill_set (insn, regno, bb);
                      }
                  }
--- 2561,2580 ----
  
  		  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
                      {
! 		      if ((call_used_regs[regno]
! 			   && regno != STACK_POINTER_REGNUM
! #if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
! 			   && regno != HARD_FRAME_POINTER_REGNUM
! #endif
! #if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
! 			   && ! (regno == ARG_POINTER_REGNUM
! 				 && fixed_regs[regno])
! #endif
! #if defined (PIC_OFFSET_TABLE_REGNUM) && !defined (PIC_OFFSET_TABLE_REG_CALL_CLOBBERED)
! 			   && ! (regno == PIC_OFFSET_TABLE_REGNUM && flag_pic)
! #endif
! 			   && regno != FRAME_POINTER_REGNUM)
! 			  || global_regs[regno])
  			handle_rd_kill_set (insn, regno, bb);
                      }
                  }

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2001-11-18  2:47 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2000-07-03  1:11 gcse fix Ulf Carlsson
2000-07-12 13:19 ` Jeffrey A Law
2001-01-14  8:39   ` Andreas Jaeger
2001-01-16 10:03     ` Maciej W. Rozycki
  -- strict thread matches above, loose matches on Subject: below --
2001-11-13 15:03 Jan Hubicka
2001-11-13 15:03 ` Richard Henderson
1998-10-19 23:17 Jeffrey A Law

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).