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]
Other format: [Raw text]

Make reload to avoid invalid subregs


Hi,
this patch should fix number of PRs related to invalid subregs
(like (subreg:SI (xmm) 4)) and reloads that often leads to silent
misscompilations.  New function subreg_representable_p is introduced
to verify all constraints under wich we would produce wrong code
and reload now deals with it.  Some code already did exist in reload to
cope with this but part of it was ifdeffed out by Dave and the other
part is still SUBREG_WORD centric.  I would like to remove it in
followup patch but would like to do so step by step.

Bootstrapped/regtested mainline on i386 and PPC
Ok for mainline/3.3/3.2?

Honza

Sat Apr 12 07:47:53 MST 2003  Jan Hubicka  <jh at suse dot cz>
			      Eric Botcazou
	* emit-rtl.c (subreg_hard_regno): Check subreg_offset_representable_p
	* reload.c (reload_inner_reg_of_subreg): Likewise.
	(find_reloads): Likewise; remove #if 0 hunk we replace.
	* rtl.h (subreg_representable_p): Declare.
	* rtlanal.c (subreg_representable_p): New function.
Index: emit-rtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/emit-rtl.c,v
retrieving revision 1.303
diff -c -3 -p -r1.303 emit-rtl.c
*** emit-rtl.c	20 Nov 2002 21:52:58 -0000	1.303
--- emit-rtl.c	12 Apr 2003 14:46:26 -0000
*************** subreg_hard_regno (x, check_mode)
*** 925,931 ****
      abort ();
    if (check_mode && ! HARD_REGNO_MODE_OK (base_regno, GET_MODE (reg)))
      abort ();
! 
    /* Catch non-congruent offsets too.  */
    byte_offset = SUBREG_BYTE (x);
    if ((byte_offset % GET_MODE_SIZE (mode)) != 0)
--- 925,935 ----
      abort ();
    if (check_mode && ! HARD_REGNO_MODE_OK (base_regno, GET_MODE (reg)))
      abort ();
! #ifdef ENABLE_CHECKING
!   if (!subreg_offset_representable_p (REGNO (reg), GET_MODE (reg),
! 			  	      SUBREG_BYTE (x), mode))
!     abort ();
! #endif
    /* Catch non-congruent offsets too.  */
    byte_offset = SUBREG_BYTE (x);
    if ((byte_offset % GET_MODE_SIZE (mode)) != 0)
Index: reload.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reload.c,v
retrieving revision 1.199.2.6
diff -c -3 -p -r1.199.2.6 reload.c
*** reload.c	26 Mar 2003 07:53:57 -0000	1.199.2.6
--- reload.c	12 Apr 2003 14:46:27 -0000
*************** reload_inner_reg_of_subreg (x, mode, out
*** 819,824 ****
--- 819,831 ----
        || REGNO (inner) >= FIRST_PSEUDO_REGISTER)
      return 0;
  
+   if (!subreg_offset_representable_p
+ 	(REGNO (SUBREG_REG (x)),
+ 		GET_MODE (SUBREG_REG (x)),
+ 		SUBREG_BYTE (x),
+ 		GET_MODE (x)))
+     return 1;
+ 
    /* If INNER is not ok for MODE, then INNER will need reloading.  */
    if (! HARD_REGNO_MODE_OK (subreg_regno (x), mode))
      return 1;
*************** find_reloads (insn, replace, ind_levels,
*** 2869,2874 ****
--- 2876,2887 ----
  	      if (GET_CODE (SUBREG_REG (operand)) == REG
  		  && REGNO (SUBREG_REG (operand)) < FIRST_PSEUDO_REGISTER)
  		{
+ 		  if (!subreg_offset_representable_p
+ 			(REGNO (SUBREG_REG (operand)),
+ 			 GET_MODE (SUBREG_REG (operand)),
+ 			 SUBREG_BYTE (operand),
+ 			 GET_MODE (operand)))
+ 		     force_reload = 1;
  		  offset += subreg_regno_offset (REGNO (SUBREG_REG (operand)),
  						 GET_MODE (SUBREG_REG (operand)),
  						 SUBREG_BYTE (operand),
*************** find_reloads (insn, replace, ind_levels,
*** 2924,2949 ****
  			  )
  #endif
  		      )
- 		  /* This following hunk of code should no longer be
- 		     needed at all with SUBREG_BYTE.  If you need this
- 		     code back, please explain to me why so I can
- 		     fix the real problem.  -DaveM */
- #if 0
- 		  /* Subreg of a hard reg which can't handle the subreg's mode
- 		     or which would handle that mode in the wrong number of
- 		     registers for subregging to work.  */
- 		  || (GET_CODE (operand) == REG
- 		      && REGNO (operand) < FIRST_PSEUDO_REGISTER
- 		      && ((GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
- 			   && (GET_MODE_SIZE (GET_MODE (operand))
- 			       > UNITS_PER_WORD)
- 			   && ((GET_MODE_SIZE (GET_MODE (operand))
- 				/ UNITS_PER_WORD)
- 			       != HARD_REGNO_NREGS (REGNO (operand),
- 						    GET_MODE (operand))))
- 			  || ! HARD_REGNO_MODE_OK (REGNO (operand) + offset,
- 						   operand_mode[i])))
- #endif
  		  )
  		force_reload = 1;
  	    }
--- 2937,2942 ----
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.375.2.4
diff -c -3 -p -r1.375.2.4 rtl.h
*** rtl.h	24 Mar 2003 17:59:36 -0000	1.375.2.4
--- rtl.h	12 Apr 2003 14:46:28 -0000
*************** extern unsigned int subreg_regno_offset 
*** 1033,1038 ****
--- 1033,1042 ----
  							 enum machine_mode, 
  							 unsigned int, 
  							 enum machine_mode));
+ extern bool subreg_representable_p 	PARAMS ((unsigned int, 
+ 							 enum machine_mode, 
+ 							 unsigned int, 
+ 							 enum machine_mode));
  extern unsigned int subreg_regno 	PARAMS ((rtx));
  
  /* 1 if RTX is a subreg containing a reg that is already known to be
Index: rtlanal.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtlanal.c,v
retrieving revision 1.140.4.2
diff -c -3 -p -r1.140.4.2 rtlanal.c
*** rtlanal.c	11 Feb 2003 20:47:56 -0000	1.140.4.2
--- rtlanal.c	12 Apr 2003 14:46:28 -0000
*************** subreg_regno_offset (xregno, xmode, offs
*** 3159,3164 ****
--- 3159,3225 ----
    return (y_offset / (mode_multiple / nregs_multiple)) * nregs_ymode;
  }
  
+ /* This function returns true when the offset is representable via
+    subreg_offset in the given regno.
+    xregno - A regno of an inner hard subreg_reg (or what will become one).
+    xmode  - The mode of xregno.
+    offset - The byte offset.
+    ymode  - The mode of a top level SUBREG (or what may become one).  */
+ bool
+ subreg_offset_representable_p (xregno, xmode, offset, ymode)
+      unsigned int xregno;
+      enum machine_mode xmode;
+      unsigned int offset;
+      enum machine_mode ymode;
+ {
+   int nregs_xmode, nregs_ymode;
+   int mode_multiple, nregs_multiple;
+   int y_offset;
+ 
+   if (xregno >= FIRST_PSEUDO_REGISTER)
+     abort ();
+ 
+   nregs_xmode = HARD_REGNO_NREGS (xregno, xmode);
+   nregs_ymode = HARD_REGNO_NREGS (xregno, ymode);
+ 
+   /* Lowpart subregs (including paradoxical) are always valid.  */
+   if (offset == subreg_lowpart_offset (ymode, xmode))
+     return true;
+ 
+ #ifdef ENABLE_CHECKING
+   /* This should always pass, otherwise we don't know how to verify the
+      constraint. 
+ 
+      These conditions may be relaxed but subreg_offset would need to be
+      redesigned.  */
+   if (GET_MODE_SIZE (xmode) % GET_MODE_SIZE (ymode)
+       || GET_MODE_SIZE (ymode) % nregs_ymode
+       || mode_for_size (GET_MODE_SIZE (ymode) / nregs_ymode,
+ 	      		MODE_INT, 0) == VOIDmode
+       || nregs_xmode % nregs_ymode)
+     abort ();
+ #endif
+ 
+   /* The XMODE value can be seen as an vector of NREGS_XMODE
+      values.  The subreg must represent an lowpart of given field.
+      Compute what field it is.  */
+   offset -= subreg_lowpart_offset (mode_for_size (GET_MODE_SIZE (ymode)
+ 			  			  / nregs_ymode,
+ 						  MODE_INT, 0), xmode);
+ 
+   /* size of ymode must not be greater than the size of xmode.  */
+   mode_multiple = GET_MODE_SIZE (xmode) / GET_MODE_SIZE (ymode);
+ 
+   y_offset = offset / GET_MODE_SIZE (ymode);
+   nregs_multiple =  nregs_xmode / nregs_ymode;
+ #ifdef ENABLE_CHECKING
+   if (offset % GET_MODE_SIZE (ymode)
+       || mode_multiple % nregs_multiple)
+     abort ();
+ #endif
+   return (!(y_offset % (mode_multiple / nregs_multiple)));
+ }
+ 
  /* Return the final regno that a subreg expression refers to.  */
  unsigned int
  subreg_regno (x)


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