This is the mail archive of the gcc@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]

[cft] subreg validation patch


On Sat, Nov 13, 2004 at 10:45:50AM +0100, Eric Botcazou wrote:
> Is it simply illegal to create non-lowpart subregs of subword pseudo regs?

Yes.

I have a rather large patch that attempts to address some of this.
I'd gotten distracted this last week with bitfield fallout, but I
promised Aldy that I'd get back to it.

Could everyone please try the following on their favorite platform
and report back with new failures?


r~



Index: combine.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/combine.c,v
retrieving revision 1.460
diff -c -p -d -r1.460 combine.c
*** combine.c	22 Oct 2004 17:05:03 -0000	1.460
--- combine.c	13 Nov 2004 22:50:29 -0000
*************** recog_for_combine (rtx *pnewpat, rtx ins
*** 9308,9323 ****
     An insn containing that will not be recognized.  */
  
  static rtx
! gen_lowpart_for_combine (enum machine_mode mode, rtx x)
  {
    rtx result;
  
!   if (GET_MODE (x) == mode)
      return x;
  
!   /* Return identity if this is a CONST or symbolic
!      reference.  */
!   if (mode == Pmode
        && (GET_CODE (x) == CONST
  	  || GET_CODE (x) == SYMBOL_REF
  	  || GET_CODE (x) == LABEL_REF))
--- 9308,9325 ----
     An insn containing that will not be recognized.  */
  
  static rtx
! gen_lowpart_for_combine (enum machine_mode omode, rtx x)
  {
+   enum machine_mode imode = GET_MODE (x);
+   unsigned int osize = GET_MODE_SIZE (omode);
+   unsigned int isize = GET_MODE_SIZE (imode);
    rtx result;
  
!   if (omode == imode)
      return x;
  
!   /* Return identity if this is a CONST or symbolic reference.  */
!   if (omode == Pmode
        && (GET_CODE (x) == CONST
  	  || GET_CODE (x) == SYMBOL_REF
  	  || GET_CODE (x) == LABEL_REF))
*************** gen_lowpart_for_combine (enum machine_mo
*** 9325,9337 ****
  
    /* We can only support MODE being wider than a word if X is a
       constant integer or has a mode the same size.  */
! 
!   if (GET_MODE_SIZE (mode) > UNITS_PER_WORD
!       && ! ((GET_MODE (x) == VOIDmode
  	     && (GET_CODE (x) == CONST_INT
  		 || GET_CODE (x) == CONST_DOUBLE))
! 	    || GET_MODE_SIZE (GET_MODE (x)) == GET_MODE_SIZE (mode)))
!     return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
  
    /* X might be a paradoxical (subreg (mem)).  In that case, gen_lowpart
       won't know what to do.  So we will strip off the SUBREG here and
--- 9327,9338 ----
  
    /* We can only support MODE being wider than a word if X is a
       constant integer or has a mode the same size.  */
!   if (GET_MODE_SIZE (omode) > UNITS_PER_WORD
!       && ! ((imode == VOIDmode
  	     && (GET_CODE (x) == CONST_INT
  		 || GET_CODE (x) == CONST_DOUBLE))
! 	    || isize == osize))
!     goto fail;
  
    /* X might be a paradoxical (subreg (mem)).  In that case, gen_lowpart
       won't know what to do.  So we will strip off the SUBREG here and
*************** gen_lowpart_for_combine (enum machine_mo
*** 9339,9349 ****
    if (GET_CODE (x) == SUBREG && MEM_P (SUBREG_REG (x)))
      {
        x = SUBREG_REG (x);
!       if (GET_MODE (x) == mode)
  	return x;
      }
  
!   result = gen_lowpart_common (mode, x);
  #ifdef CANNOT_CHANGE_MODE_CLASS
    if (result != 0 && GET_CODE (result) == SUBREG)
      record_subregs_of_mode (result);
--- 9340,9351 ----
    if (GET_CODE (x) == SUBREG && MEM_P (SUBREG_REG (x)))
      {
        x = SUBREG_REG (x);
!       if (GET_MODE (x) == omode)
  	return x;
      }
  
!   result = gen_lowpart_common (omode, x);
! 
  #ifdef CANNOT_CHANGE_MODE_CLASS
    if (result != 0 && GET_CODE (result) == SUBREG)
      record_subregs_of_mode (result);
*************** gen_lowpart_for_combine (enum machine_mo
*** 9359,9391 ****
        /* Refuse to work on a volatile memory ref or one with a mode-dependent
  	 address.  */
        if (MEM_VOLATILE_P (x) || mode_dependent_address_p (XEXP (x, 0)))
! 	return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
  
        /* If we want to refer to something bigger than the original memref,
  	 generate a paradoxical subreg instead.  That will force a reload
  	 of the original memref X.  */
!       if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode))
! 	return gen_rtx_SUBREG (mode, x, 0);
  
        if (WORDS_BIG_ENDIAN)
! 	offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
! 		  - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));
  
        if (BYTES_BIG_ENDIAN)
! 	{
! 	  /* Adjust the address so that the address-after-the-data is
! 	     unchanged.  */
! 	  offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
! 		     - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
! 	}
  
!       return adjust_address_nv (x, mode, offset);
      }
  
    /* If X is a comparison operator, rewrite it in a new mode.  This
       probably won't match, but may allow further simplifications.  */
    else if (COMPARISON_P (x))
!     return gen_rtx_fmt_ee (GET_CODE (x), mode, XEXP (x, 0), XEXP (x, 1));
  
    /* If we couldn't simplify X any other way, just enclose it in a
       SUBREG.  Normally, this SUBREG won't match, but some patterns may
--- 9361,9388 ----
        /* Refuse to work on a volatile memory ref or one with a mode-dependent
  	 address.  */
        if (MEM_VOLATILE_P (x) || mode_dependent_address_p (XEXP (x, 0)))
! 	goto fail;
  
        /* If we want to refer to something bigger than the original memref,
  	 generate a paradoxical subreg instead.  That will force a reload
  	 of the original memref X.  */
!       if (isize < osize)
! 	return gen_rtx_SUBREG (omode, x, 0);
  
        if (WORDS_BIG_ENDIAN)
! 	offset = MAX (isize, UNITS_PER_WORD) - MAX (osize, UNITS_PER_WORD);
  
+       /* Adjust the address so that the address-after-the-data is unchanged. */
        if (BYTES_BIG_ENDIAN)
! 	offset -= MIN (UNITS_PER_WORD, osize) - MIN (UNITS_PER_WORD, isize);
  
!       return adjust_address_nv (x, omode, offset);
      }
  
    /* If X is a comparison operator, rewrite it in a new mode.  This
       probably won't match, but may allow further simplifications.  */
    else if (COMPARISON_P (x))
!     return gen_rtx_fmt_ee (GET_CODE (x), omode, XEXP (x, 0), XEXP (x, 1));
  
    /* If we couldn't simplify X any other way, just enclose it in a
       SUBREG.  Normally, this SUBREG won't match, but some patterns may
*************** gen_lowpart_for_combine (enum machine_mo
*** 9394,9414 ****
      {
        int offset = 0;
        rtx res;
-       enum machine_mode sub_mode = GET_MODE (x);
  
!       offset = subreg_lowpart_offset (mode, sub_mode);
!       if (sub_mode == VOIDmode)
  	{
! 	  sub_mode = int_mode_for_mode (mode);
! 	  x = gen_lowpart_common (sub_mode, x);
! 	  if (x == 0)
! 	    return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
  	}
!       res = simplify_gen_subreg (mode, x, sub_mode, offset);
        if (res)
  	return res;
-       return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
      }
  }
  
  /* These routines make binary and unary operations by first seeing if they
--- 9391,9412 ----
      {
        int offset = 0;
        rtx res;
  
!       offset = subreg_lowpart_offset (omode, imode);
!       if (imode == VOIDmode)
  	{
! 	  imode = int_mode_for_mode (omode);
! 	  x = gen_lowpart_common (imode, x);
! 	  if (x == NULL)
! 	    goto fail;
  	}
!       res = simplify_gen_subreg (omode, x, imode, offset);
        if (res)
  	return res;
      }
+ 
+  fail:
+   return gen_rtx_CLOBBER (imode, const0_rtx);
  }
  
  /* These routines make binary and unary operations by first seeing if they
Index: cse.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cse.c,v
retrieving revision 1.320
diff -c -p -d -r1.320 cse.c
*** cse.c	2 Nov 2004 17:59:41 -0000	1.320
--- cse.c	13 Nov 2004 22:50:33 -0000
*************** record_jump_equiv (rtx insn, int taken)
*** 4329,4334 ****
--- 4329,4346 ----
    record_jump_cond (code, mode, op0, op1, reversed_nonequality);
  }
  
+ /* Yet another form of subreg creation.  In this case, we want something in
+    MODE, and we should assume OP has MODE iff it is naturally modeless.  */
+ 
+ static rtx
+ record_jump_cond_subreg (enum machine_mode mode, rtx op)
+ {
+   enum machine_mode op_mode = GET_MODE (op);
+   if (op_mode == mode || op_mode == VOIDmode)
+     return op;
+   return lowpart_subreg (mode, op, op_mode);
+ }
+ 
  /* We know that comparison CODE applied to OP0 and OP1 in MODE is true.
     REVERSED_NONEQUALITY is nonzero if CODE had to be swapped.
     Make any useful entries we can with that information.  Called from
*************** record_jump_cond (enum rtx_code code, en
*** 4353,4363 ****
  	  > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))))
      {
        enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
!       rtx tem = gen_lowpart (inner_mode, op1);
! 
!       record_jump_cond (code, mode, SUBREG_REG (op0),
! 			tem ? tem : gen_rtx_SUBREG (inner_mode, op1, 0),
! 			reversed_nonequality);
      }
  
    if (code == EQ && GET_CODE (op1) == SUBREG
--- 4365,4374 ----
  	  > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))))
      {
        enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
!       rtx tem = record_jump_cond_subreg (inner_mode, op1);
!       if (tem)
! 	record_jump_cond (code, mode, SUBREG_REG (op0), tem,
! 			  reversed_nonequality);
      }
  
    if (code == EQ && GET_CODE (op1) == SUBREG
*************** record_jump_cond (enum rtx_code code, en
*** 4365,4375 ****
  	  > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1)))))
      {
        enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
!       rtx tem = gen_lowpart (inner_mode, op0);
! 
!       record_jump_cond (code, mode, SUBREG_REG (op1),
! 			tem ? tem : gen_rtx_SUBREG (inner_mode, op0, 0),
! 			reversed_nonequality);
      }
  
    /* Similarly, if this is an NE comparison, and either is a SUBREG
--- 4376,4385 ----
  	  > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1)))))
      {
        enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
!       rtx tem = record_jump_cond_subreg (inner_mode, op0);
!       if (tem)
! 	record_jump_cond (code, mode, SUBREG_REG (op1), tem,
! 			  reversed_nonequality);
      }
  
    /* Similarly, if this is an NE comparison, and either is a SUBREG
*************** record_jump_cond (enum rtx_code code, en
*** 4385,4395 ****
  	  < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))))
      {
        enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
!       rtx tem = gen_lowpart (inner_mode, op1);
! 
!       record_jump_cond (code, mode, SUBREG_REG (op0),
! 			tem ? tem : gen_rtx_SUBREG (inner_mode, op1, 0),
! 			reversed_nonequality);
      }
  
    if (code == NE && GET_CODE (op1) == SUBREG
--- 4395,4404 ----
  	  < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))))
      {
        enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
!       rtx tem = record_jump_cond_subreg (inner_mode, op1);
!       if (tem)
! 	record_jump_cond (code, mode, SUBREG_REG (op0), tem,
! 			  reversed_nonequality);
      }
  
    if (code == NE && GET_CODE (op1) == SUBREG
*************** record_jump_cond (enum rtx_code code, en
*** 4398,4408 ****
  	  < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1)))))
      {
        enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
!       rtx tem = gen_lowpart (inner_mode, op0);
! 
!       record_jump_cond (code, mode, SUBREG_REG (op1),
! 			tem ? tem : gen_rtx_SUBREG (inner_mode, op0, 0),
! 			reversed_nonequality);
      }
  
    /* Hash both operands.  */
--- 4407,4416 ----
  	  < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1)))))
      {
        enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
!       rtx tem = record_jump_cond_subreg (inner_mode, op0);
!       if (tem)
! 	record_jump_cond (code, mode, SUBREG_REG (op1), tem,
! 			  reversed_nonequality);
      }
  
    /* Hash both operands.  */
Index: emit-rtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/emit-rtl.c,v
retrieving revision 1.423
diff -c -p -d -r1.423 emit-rtl.c
*** emit-rtl.c	9 Nov 2004 17:46:06 -0000	1.423
--- emit-rtl.c	13 Nov 2004 22:50:34 -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,688 ----
    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)
+     ;
+   /* 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 all of these rules collected in
+      subreg_offset_representable_p.  */
+   if (reg && REG_P (reg) && HARD_REGISTER_P (reg))
+     return subreg_offset_representable_p (REGNO (reg), 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: expmed.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expmed.c,v
retrieving revision 1.203
diff -c -p -d -r1.203 expmed.c
*** expmed.c	8 Nov 2004 19:18:16 -0000	1.203
--- expmed.c	13 Nov 2004 22:50:35 -0000
*************** extract_bit_field (rtx str_rtx, unsigned
*** 1233,1254 ****
      {
        if (mode1 != GET_MODE (op0))
  	{
! 	  if (GET_CODE (op0) == SUBREG)
  	    {
! 	      if (GET_MODE (SUBREG_REG (op0)) == mode1
! 		  || GET_MODE_CLASS (mode1) == MODE_INT
! 		  || GET_MODE_CLASS (mode1) == MODE_PARTIAL_INT)
! 		op0 = SUBREG_REG (op0);
! 	      else
! 		/* Else we've got some float mode source being extracted into
! 		   a different float mode destination -- this combination of
! 		   subregs results in Severe Tire Damage.  */
  		goto no_subreg_mode_swap;
  	    }
- 	  if (REG_P (op0))
- 	    op0 = gen_rtx_SUBREG (mode1, op0, byte_offset);
- 	  else
- 	    op0 = adjust_address (op0, mode1, offset);
  	}
        if (mode1 != mode)
  	return convert_to_mode (tmode, op0, unsignedp);
--- 1233,1248 ----
      {
        if (mode1 != GET_MODE (op0))
  	{
! 	  if (MEM_P (op0))
! 	    op0 = adjust_address (op0, mode1, offset);
! 	  else
  	    {
! 	      rtx sub = simplify_gen_subreg (mode1, op0, GET_MODE (op0),
! 					     byte_offset);
! 	      if (sub == NULL)
  		goto no_subreg_mode_swap;
+ 	      op0 = sub;
  	    }
  	}
        if (mode1 != mode)
  	return convert_to_mode (tmode, op0, unsignedp);
*************** extract_bit_field (rtx str_rtx, unsigned
*** 1628,1646 ****
      return spec_target;
    if (GET_MODE (target) != tmode && GET_MODE (target) != mode)
      {
!       /* If the target mode is floating-point, first convert to the
! 	 integer mode of that size and then access it as a floating-point
! 	 value via a SUBREG.  */
!       if (GET_MODE_CLASS (tmode) != MODE_INT
! 	  && GET_MODE_CLASS (tmode) != MODE_PARTIAL_INT)
  	{
  	  target = convert_to_mode (mode_for_size (GET_MODE_BITSIZE (tmode),
  						   MODE_INT, 0),
  				    target, unsignedp);
  	  return gen_lowpart (tmode, target);
  	}
!       else
! 	return convert_to_mode (tmode, target, unsignedp);
      }
    return target;
  }
--- 1622,1662 ----
      return spec_target;
    if (GET_MODE (target) != tmode && GET_MODE (target) != mode)
      {
!       /* If the target mode is complex, then extract the two scalar elements
! 	 from the value now.  Creating (subreg:SC (reg:DI) 0), as we would do
! 	 with the clause below, will cause gen_realpart or gen_imagpart to
! 	 fail, since those functions must return lvalues.  */
!       if (COMPLEX_MODE_P (tmode))
  	{
+ 	  rtx realpart, imagpart;
+ 	  enum machine_mode itmode = GET_MODE_INNER (tmode);
+ 
  	  target = convert_to_mode (mode_for_size (GET_MODE_BITSIZE (tmode),
  						   MODE_INT, 0),
  				    target, unsignedp);
+ 
+ 	  realpart = extract_bit_field (target, GET_MODE_BITSIZE (itmode), 0,
+ 					unsignedp, NULL, itmode, itmode);
+ 	  imagpart = extract_bit_field (target, GET_MODE_BITSIZE (itmode),
+ 					GET_MODE_BITSIZE (itmode), unsignedp,
+ 					NULL, itmode, itmode);
+ 
+ 	  return gen_rtx_CONCAT (tmode, realpart, imagpart);
+ 	}
+ 
+       /* If the target mode is not a scalar integral, first convert to the
+ 	 integer mode of that size and then access it as a floating-point
+ 	 value via a SUBREG.  */
+       if (!SCALAR_INT_MODE_P (tmode))
+ 	{
+ 	  enum machine_mode smode
+ 	    = mode_for_size (GET_MODE_BITSIZE (tmode), MODE_INT, 0);
+ 	  target = convert_to_mode (smode, target, unsignedp);
+ 	  target = force_reg (smode, target);
  	  return gen_lowpart (tmode, target);
  	}
! 
!       return convert_to_mode (tmode, target, unsignedp);
      }
    return target;
  }
Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.739
diff -c -p -d -r1.739 expr.c
*** expr.c	12 Nov 2004 06:59:47 -0000	1.739
--- expr.c	13 Nov 2004 22:50:37 -0000
*************** emit_move_insn_1 (rtx x, rtx y)
*** 2578,2584 ****
  {
    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);
  
--- 2578,2583 ----
*************** emit_move_insn_1 (rtx x, rtx y)
*** 2587,2606 ****
        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;
--- 2586,2606 ----
        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)
*** 2614,2622 ****
  			       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)
--- 2614,2620 ----
  			       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)
*** 2624,2634 ****
  
  #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,
--- 2622,2631 ----
  
  #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)
*** 2679,2720 ****
  	     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);
! 			}
  		    }
  		}
  	    }
--- 2676,2707 ----
  	     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.522
diff -c -p -d -r1.522 rtl.h
*** rtl.h	11 Nov 2004 23:10:10 -0000	1.522
--- rtl.h	13 Nov 2004 22:50:37 -0000
*************** extern rtx emit_copy_of_insn_after (rtx,
*** 1372,1378 ****
  extern void set_reg_attrs_from_mem (rtx, rtx);
  extern void set_mem_attrs_from_reg (rtx, rtx);
  extern void set_reg_attrs_for_parm (rtx, rtx);
- extern void set_reg_pointer_align (rtx, unsigned int);
  extern int mem_expr_equal_p (tree, tree);
  
  /* In rtl.c */
--- 1372,1377 ----
*************** extern rtx delete_insn_and_edges (rtx);
*** 1989,1994 ****
--- 1988,1995 ----
  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.207
diff -c -p -d -r1.207 simplify-rtx.c
*** simplify-rtx.c	28 Oct 2004 12:47:21 -0000	1.207
--- simplify-rtx.c	13 Nov 2004 22:50:38 -0000
*************** simplify_subreg (enum machine_mode outer
*** 3641,3652 ****
  	}
  
        /* 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
--- 3641,3654 ----
  	}
  
        /* 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
*** 3723,3731 ****
        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.  */
--- 3725,3733 ----
        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
*** 3773,3789 ****
  		     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)
--- 3775,3780 ----
*************** simplify_gen_subreg (enum machine_mode o
*** 3793,3800 ****
        || (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
--- 3784,3795 ----
        || (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]