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]

validate subregs, part 6


Final part.  Actual validation happens here.

Also present are three bits of code that ask the validator if what
they are considering is legal, and if not do something else.


r~


        * rtl.h (validate_subreg): Declare.
        * emit-rtl.c (validate_subreg): New.
        (gen_rtx_SUBREG): Use it.
        * simplify-rtx.c (simplify_subreg): Likewise.
        (simplify_gen_subreg): Likewise.  Remove duplicate asserts.
        * expr.c (emit_move_insn_1): Tidy complex move code.  Use memory
        fallback whenever gen_realpart/gen_imagpart would not be able to
        create SUBREGs.

Index: emit-rtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/emit-rtl.c,v
retrieving revision 1.427
diff -c -p -d -r1.427 emit-rtl.c
*** emit-rtl.c	23 Nov 2004 23:10:16 -0000	1.427
--- emit-rtl.c	24 Nov 2004 00:05:08 -0000
*************** gen_const_mem (enum machine_mode mode, r
*** 607,626 ****
    return mem;
  }
  
! rtx
! gen_rtx_SUBREG (enum machine_mode mode, rtx reg, int offset)
  {
!   /* This is the most common failure type.
!      Catch it early so we can see who does it.  */
!   gcc_assert (!(offset % GET_MODE_SIZE (mode)));
  
!   /* This check isn't usable right now because combine will
!      throw arbitrary crap like a CALL into a SUBREG in
!      gen_lowpart_for_combine so we must just eat it.  */
! #if 0
!   /* Check for this too.  */
!   gcc_assert (offset < GET_MODE_SIZE (GET_MODE (reg)));
  #endif
    return gen_rtx_raw_SUBREG (mode, reg, offset);
  }
  
--- 607,704 ----
    return mem;
  }
  
! /* We want to create (subreg:OMODE (obj:IMODE) OFFSET).  Return true if
!    this construct would be valid, and false otherwise.  */
! 
! bool
! validate_subreg (enum machine_mode omode, enum machine_mode imode,
! 		 rtx reg, unsigned int offset)
  {
!   unsigned int isize = GET_MODE_SIZE (imode);
!   unsigned int osize = GET_MODE_SIZE (omode);
  
!   /* All subregs must be aligned.  */
!   if (offset % osize != 0)
!     return false;
! 
!   /* The subreg offset cannot be outside the inner object.  */
!   if (offset >= isize)
!     return false;
! 
!   /* ??? This should not be here.  Temporarily continue to allow word_mode
!      subregs of anything.  The most common offender is (subreg:SI (reg:DF)).
!      Generally, backends are doing something sketchy but it'll take time to
!      fix them all.  */
!   if (omode == word_mode)
!     ;
!   /* ??? Similarly, e.g. with (subreg:DF (reg:TI)).  Though store_bit_field
!      is the culprit here, and not the backends.  */
!   else if (osize >= UNITS_PER_WORD && isize >= osize)
!     ;
!   /* Allow component subregs of complex and vector.  Though given the below
!      extraction rules, it's not always clear what that means.  */
!   else if ((COMPLEX_MODE_P (imode) || VECTOR_MODE_P (imode))
! 	   && GET_MODE_INNER (imode) == omode)
!     ;
!   /* ??? x86 sse code makes heavy use of *paradoxical* vector subregs,
!      i.e. (subreg:V4SF (reg:SF) 0).  This surely isn't the cleanest way to
!      represent this.  It's questionable if this ought to be represented at
!      all -- why can't this all be hidden in post-reload splitters that make
!      arbitrarily mode changes to the registers themselves.  */
!   else if (VECTOR_MODE_P (omode) && GET_MODE_INNER (omode) == imode)
!     ;
!   /* Subregs involving floating point modes are not allowed to
!      change size.  Therefore (subreg:DI (reg:DF) 0) is fine, but
!      (subreg:SI (reg:DF) 0) isn't.  */
!   else if (FLOAT_MODE_P (imode) || FLOAT_MODE_P (omode))
!     {
!       if (isize != osize)
! 	return false;
!     }
! 
!   /* Paradoxical subregs must have offset zero.  */
!   if (osize > isize)
!     return offset == 0;
! 
!   /* This is a normal subreg.  Verify that the offset is representable.  */
! 
!   /* For hard registers, we already have most of these rules collected in
!      subreg_offset_representable_p.  */
!   if (reg && REG_P (reg) && HARD_REGISTER_P (reg))
!     {
!       unsigned int regno = REGNO (reg);
! 
! #ifdef CANNOT_CHANGE_MODE_CLASS
!       if ((COMPLEX_MODE_P (imode) || VECTOR_MODE_P (imode))
! 	  && GET_MODE_INNER (imode) == omode)
! 	;
!       else if (REG_CANNOT_CHANGE_MODE_P (regno, imode, omode))
! 	return false;
  #endif
+ 
+       return subreg_offset_representable_p (regno, imode, offset, omode);
+     }
+ 
+   /* For pseudo registers, we want most of the same checks.  Namely:
+      If the register no larger than a word, the subreg must be lowpart.
+      If the register is larger than a word, the subreg must be the lowpart
+      of a subword.  A subreg does *not* perform arbitrary bit extraction.
+      Given that we've already checked mode/offset alignment, we only have
+      to check subword subregs here.  */
+   if (osize < UNITS_PER_WORD)
+     {
+       enum machine_mode wmode = isize > UNITS_PER_WORD ? word_mode : imode;
+       unsigned int low_off = subreg_lowpart_offset (omode, wmode);
+       if (offset % UNITS_PER_WORD != low_off)
+ 	return false;
+     }
+   return true;
+ }
+ 
+ rtx
+ gen_rtx_SUBREG (enum machine_mode mode, rtx reg, int offset)
+ {
+   gcc_assert (validate_subreg (mode, GET_MODE (reg), reg, offset));
    return gen_rtx_raw_SUBREG (mode, reg, offset);
  }
  
Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.741
diff -c -p -d -r1.741 expr.c
*** expr.c	14 Nov 2004 13:05:19 -0000	1.741
--- expr.c	24 Nov 2004 00:05:10 -0000
*************** emit_move_insn_1 (rtx x, rtx y)
*** 2647,2653 ****
  {
    enum machine_mode mode = GET_MODE (x);
    enum machine_mode submode;
-   enum mode_class class = GET_MODE_CLASS (mode);
  
    gcc_assert ((unsigned int) mode < (unsigned int) MAX_MACHINE_MODE);
  
--- 2647,2652 ----
*************** emit_move_insn_1 (rtx x, rtx y)
*** 2656,2675 ****
        emit_insn (GEN_FCN (mov_optab->handlers[(int) mode].insn_code) (x, y));
  
    /* Expand complex moves by moving real part and imag part, if possible.  */
!   else if ((class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)
  	   && BLKmode != (submode = GET_MODE_INNER (mode))
  	   && (mov_optab->handlers[(int) submode].insn_code
  	       != CODE_FOR_nothing))
      {
        /* Don't split destination if it is a stack push.  */
!       int stack = push_operand (x, GET_MODE (x));
  
  #ifdef PUSH_ROUNDING
        /* In case we output to the stack, but the size is smaller than the
  	 machine can push exactly, we need to use move instructions.  */
!       if (stack
! 	  && (PUSH_ROUNDING (GET_MODE_SIZE (submode))
! 	      != GET_MODE_SIZE (submode)))
  	{
  	  rtx temp;
  	  HOST_WIDE_INT offset1, offset2;
--- 2655,2675 ----
        emit_insn (GEN_FCN (mov_optab->handlers[(int) mode].insn_code) (x, y));
  
    /* Expand complex moves by moving real part and imag part, if possible.  */
!   else if (COMPLEX_MODE_P (mode)
  	   && BLKmode != (submode = GET_MODE_INNER (mode))
  	   && (mov_optab->handlers[(int) submode].insn_code
  	       != CODE_FOR_nothing))
      {
+       unsigned int modesize = GET_MODE_SIZE (mode);
+       unsigned int submodesize = GET_MODE_SIZE (submode);
+ 
        /* Don't split destination if it is a stack push.  */
!       int stack = push_operand (x, mode);
  
  #ifdef PUSH_ROUNDING
        /* In case we output to the stack, but the size is smaller than the
  	 machine can push exactly, we need to use move instructions.  */
!       if (stack && PUSH_ROUNDING (submodesize) != submodesize)
  	{
  	  rtx temp;
  	  HOST_WIDE_INT offset1, offset2;
*************** emit_move_insn_1 (rtx x, rtx y)
*** 2683,2691 ****
  			       add_optab,
  #endif
  			       stack_pointer_rtx,
! 			       GEN_INT
! 				 (PUSH_ROUNDING
! 				  (GET_MODE_SIZE (GET_MODE (x)))),
  			       stack_pointer_rtx, 0, OPTAB_LIB_WIDEN);
  
  	  if (temp != stack_pointer_rtx)
--- 2683,2689 ----
  			       add_optab,
  #endif
  			       stack_pointer_rtx,
! 			       GEN_INT (PUSH_ROUNDING (modesize)),
  			       stack_pointer_rtx, 0, OPTAB_LIB_WIDEN);
  
  	  if (temp != stack_pointer_rtx)
*************** emit_move_insn_1 (rtx x, rtx y)
*** 2693,2703 ****
  
  #ifdef STACK_GROWS_DOWNWARD
  	  offset1 = 0;
! 	  offset2 = GET_MODE_SIZE (submode);
  #else
! 	  offset1 = -PUSH_ROUNDING (GET_MODE_SIZE (GET_MODE (x)));
! 	  offset2 = (-PUSH_ROUNDING (GET_MODE_SIZE (GET_MODE (x)))
! 		     + GET_MODE_SIZE (submode));
  #endif
  
  	  emit_move_insn (change_address (x, submode,
--- 2691,2700 ----
  
  #ifdef STACK_GROWS_DOWNWARD
  	  offset1 = 0;
! 	  offset2 = submodesize;
  #else
! 	  offset1 = -PUSH_ROUNDING (modesize);
! 	  offset2 = -PUSH_ROUNDING (modesize) + submodesize;
  #endif
  
  	  emit_move_insn (change_address (x, submode,
*************** emit_move_insn_1 (rtx x, rtx y)
*** 2748,2789 ****
  	     memory and reload.  FIXME, we should see about using extract and
  	     insert on integer registers, but complex short and complex char
  	     variables should be rarely used.  */
! 	  if (GET_MODE_BITSIZE (mode) < 2 * BITS_PER_WORD
! 	      && (reload_in_progress | reload_completed) == 0)
  	    {
! 	      int packed_dest_p
! 		= (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER);
! 	      int packed_src_p
! 		= (REG_P (y) && REGNO (y) < FIRST_PSEUDO_REGISTER);
! 
! 	      if (packed_dest_p || packed_src_p)
  		{
! 		  enum mode_class reg_class = ((class == MODE_COMPLEX_FLOAT)
! 					       ? MODE_FLOAT : MODE_INT);
! 
  		  enum machine_mode reg_mode
! 		    = mode_for_size (GET_MODE_BITSIZE (mode), reg_class, 1);
! 
! 		  if (reg_mode != BLKmode)
! 		    {
! 		      rtx mem = assign_stack_temp (reg_mode,
! 						   GET_MODE_SIZE (mode), 0);
! 		      rtx cmem = adjust_address (mem, mode, 0);
  
! 		      if (packed_dest_p)
! 			{
! 			  rtx sreg = gen_rtx_SUBREG (reg_mode, x, 0);
  
! 			  emit_move_insn_1 (cmem, y);
! 			  return emit_move_insn_1 (sreg, mem);
! 			}
! 		      else
! 			{
! 			  rtx sreg = gen_rtx_SUBREG (reg_mode, y, 0);
  
! 			  emit_move_insn_1 (mem, sreg);
! 			  return emit_move_insn_1 (x, cmem);
! 			}
  		    }
  		}
  	    }
--- 2745,2776 ----
  	     memory and reload.  FIXME, we should see about using extract and
  	     insert on integer registers, but complex short and complex char
  	     variables should be rarely used.  */
! 	  if ((reload_in_progress | reload_completed) == 0
! 	      && (!validate_subreg (submode, mode, NULL, submodesize)
! 		  || !validate_subreg (submode, mode, NULL, 0)))
  	    {
! 	      if (REG_P (x) || REG_P (y))
  		{
! 		  rtx mem, cmem;
  		  enum machine_mode reg_mode
! 		    = mode_for_size (GET_MODE_BITSIZE (mode), MODE_INT, 1);
  
! 		  gcc_assert (reg_mode != BLKmode);
  
! 		  mem = assign_stack_temp (reg_mode, modesize, 0);
! 		  cmem = adjust_address (mem, mode, 0);
  
! 		  if (REG_P (x))
! 		    {
! 		      rtx sreg = gen_rtx_SUBREG (reg_mode, x, 0);
! 		      emit_move_insn_1 (cmem, y);
! 		      return emit_move_insn_1 (sreg, mem);
! 		    }
! 		  else
! 		    {
! 		      rtx sreg = gen_rtx_SUBREG (reg_mode, y, 0);
! 		      emit_move_insn_1 (mem, sreg);
! 		      return emit_move_insn_1 (x, cmem);
  		    }
  		}
  	    }
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.527
diff -c -p -d -r1.527 rtl.h
*** rtl.h	23 Nov 2004 23:10:18 -0000	1.527
--- rtl.h	24 Nov 2004 00:05:12 -0000
*************** extern rtx delete_insn_and_edges (rtx);
*** 1964,1969 ****
--- 1964,1971 ----
  extern void delete_insn_chain_and_edges (rtx, rtx);
  extern rtx gen_lowpart_SUBREG (enum machine_mode, rtx);
  extern rtx gen_const_mem (enum machine_mode, rtx);
+ extern bool validate_subreg (enum machine_mode, enum machine_mode,
+ 			     rtx, unsigned int);
  
  /* In combine.c */
  extern int combine_instructions (rtx, unsigned int);
Index: simplify-rtx.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/simplify-rtx.c,v
retrieving revision 1.210
diff -c -p -d -r1.210 simplify-rtx.c
*** simplify-rtx.c	23 Nov 2004 23:03:15 -0000	1.210
--- simplify-rtx.c	24 Nov 2004 00:05:13 -0000
*************** simplify_subreg (enum machine_mode outer
*** 3642,3653 ****
  	}
  
        /* Recurse for further possible simplifications.  */
!       newx = simplify_subreg (outermode, SUBREG_REG (op),
! 			     GET_MODE (SUBREG_REG (op)),
! 			     final_offset);
        if (newx)
  	return newx;
!       return gen_rtx_SUBREG (outermode, SUBREG_REG (op), final_offset);
      }
  
    /* SUBREG of a hard register => just change the register number
--- 3642,3655 ----
  	}
  
        /* Recurse for further possible simplifications.  */
!       newx = simplify_subreg (outermode, SUBREG_REG (op), innermostmode,
! 			      final_offset);
        if (newx)
  	return newx;
!       if (validate_subreg (outermode, innermostmode,
! 			   SUBREG_REG (op), final_offset))
!         return gen_rtx_SUBREG (outermode, SUBREG_REG (op), final_offset);
!       return NULL_RTX;
      }
  
    /* SUBREG of a hard register => just change the register number
*************** simplify_subreg (enum machine_mode outer
*** 3725,3733 ****
        res = simplify_subreg (outermode, part, GET_MODE (part), final_offset);
        if (res)
  	return res;
!       /* We can at least simplify it by referring directly to the
! 	 relevant part.  */
!       return gen_rtx_SUBREG (outermode, part, final_offset);
      }
  
    /* Optimize SUBREG truncations of zero and sign extended values.  */
--- 3727,3735 ----
        res = simplify_subreg (outermode, part, GET_MODE (part), final_offset);
        if (res)
  	return res;
!       if (validate_subreg (outermode, GET_MODE (part), part, final_offset))
!         return gen_rtx_SUBREG (outermode, part, final_offset);
!       return NULL_RTX;
      }
  
    /* Optimize SUBREG truncations of zero and sign extended values.  */
*************** simplify_gen_subreg (enum machine_mode o
*** 3775,3791 ****
  		     enum machine_mode innermode, unsigned int byte)
  {
    rtx newx;
-   /* Little bit of sanity checking.  */
-   gcc_assert (innermode != VOIDmode);
-   gcc_assert (outermode != VOIDmode);
-   gcc_assert (innermode != BLKmode);
-   gcc_assert (outermode != BLKmode);
- 
-   gcc_assert (GET_MODE (op) == innermode
- 	      || GET_MODE (op) == VOIDmode);
- 
-   gcc_assert ((byte % GET_MODE_SIZE (outermode)) == 0);
-   gcc_assert (byte < GET_MODE_SIZE (innermode));
  
    newx = simplify_subreg (outermode, op, innermode, byte);
    if (newx)
--- 3777,3782 ----
*************** simplify_gen_subreg (enum machine_mode o
*** 3795,3802 ****
        || (REG_P (op) && REGNO (op) < FIRST_PSEUDO_REGISTER))
      return NULL_RTX;
  
!   return gen_rtx_SUBREG (outermode, op, byte);
  }
  /* Simplify X, an rtx expression.
  
     Return the simplified expression or NULL if no simplifications
--- 3786,3797 ----
        || (REG_P (op) && REGNO (op) < FIRST_PSEUDO_REGISTER))
      return NULL_RTX;
  
!   if (validate_subreg (outermode, innermode, op, byte))
!     return gen_rtx_SUBREG (outermode, op, byte);
! 
!   return NULL_RTX;
  }
+ 
  /* Simplify X, an rtx expression.
  
     Return the simplified expression or NULL if no simplifications


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