Patchwork [ARM] Fix PR50022

login
register
mail settings
Submitter Ramana Radhakrishnan
Date Aug. 12, 2011, 9:28 a.m.
Message ID <CACUk7=WO9+qrZ_3ne-m9sQo+iyz=NF-pJf1urrug3gtoGaNDiA@mail.gmail.com>
Download mbox | patch
Permalink /patch/109805/
State New
Headers show

Comments

Ramana Radhakrishnan - Aug. 12, 2011, 9:28 a.m.
On 12 August 2011 10:19, Ramana Radhakrishnan
<ramana.radhakrishnan@linaro.org> wrote:
> Hi,
>
> The attached patch fixes up PR50022 which exposed a problem in my reworking

And with the patch even :( ...

Ramana

2011-08-12  Ramana Radhakrishnan  <ramana.radhakrishnan@linaro.org>

       PR target/50022
       * config/arm/arm.c (output_move_double): Add 2 parameters
       to count the number of insns emitted and whether to emit or not.
       Use the flag to decide when to emit and count number of instructions
       that will be emitted.
       Handle case where output_move_double might be called for calculating
       lengths with an invalid constant.
       (arm_count_output_move_double_insns): Define.
       * config/arm/arm-protos.h (arm_count_output_move_double_insns): Declare.
       (output_move_double): Adjust prototype.
       * config/arm/vfp.md ("*movdi_vfp"): Adjust call to
       output_move_double.
       ("*movdi_vfp_cortexa8"): Likewise and add attribute
       for ce_count.
       * config/arm/arm.md ("*arm_movdi"): Adjust call to output_move_double.
       ("*movdf_soft_insn"): Likewise.
       * config/arm/cirrus.md ("*cirrus_arm_movdi"): Likewise.
       ("*cirrus_thumb2_movdi"): Likewise.
       ("*thumb2_cirrus_movdf_hard_insn"): Likewise.
       ("*cirrus_movdf_hard_insn"): Likewise.
       * config/arm/neon.md (*neon_mov<mode> VD): Likewise.
       * config/arm/iwmmxt.md ("*iwmmxt_arm_movdi"): Likewise.
       ("mov<mode>_internal VMMX"): Likewise.
Richard Earnshaw - Aug. 12, 2011, 9:39 a.m.
On 12/08/11 10:28, Ramana Radhakrishnan wrote:
> On 12 August 2011 10:19, Ramana Radhakrishnan
> <ramana.radhakrishnan@linaro.org> wrote:
>> Hi,
>>
>> The attached patch fixes up PR50022 which exposed a problem in my reworking
> 
> And with the patch even :( ...
> 
> Ramana
> 
> 2011-08-12  Ramana Radhakrishnan  <ramana.radhakrishnan@linaro.org>
> 
>        PR target/50022
>        * config/arm/arm.c (output_move_double): Add 2 parameters
>        to count the number of insns emitted and whether to emit or not.
>        Use the flag to decide when to emit and count number of instructions
>        that will be emitted.
>        Handle case where output_move_double might be called for calculating
>        lengths with an invalid constant.
>        (arm_count_output_move_double_insns): Define.
>        * config/arm/arm-protos.h (arm_count_output_move_double_insns): Declare.
>        (output_move_double): Adjust prototype.
>        * config/arm/vfp.md ("*movdi_vfp"): Adjust call to
>        output_move_double.
>        ("*movdi_vfp_cortexa8"): Likewise and add attribute
>        for ce_count.
>        * config/arm/arm.md ("*arm_movdi"): Adjust call to output_move_double.
>        ("*movdf_soft_insn"): Likewise.
>        * config/arm/cirrus.md ("*cirrus_arm_movdi"): Likewise.
>        ("*cirrus_thumb2_movdi"): Likewise.
>        ("*thumb2_cirrus_movdf_hard_insn"): Likewise.
>        ("*cirrus_movdf_hard_insn"): Likewise.
>        * config/arm/neon.md (*neon_mov<mode> VD): Likewise.
>        * config/arm/iwmmxt.md ("*iwmmxt_arm_movdi"): Likewise.
>        ("mov<mode>_internal VMMX"): Likewise.
> 

Use a bool for "emit".  Otherwise OK.

R.

> 
> final-pr50022-patch.txt
> 
> 
> diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
> index 2f7c508..d99d1ce 100644
> --- a/gcc/config/arm/arm-protos.h
> +++ b/gcc/config/arm/arm-protos.h
> @@ -131,8 +131,9 @@ extern const char *output_mov_long_double_arm_from_fpa (rtx *);
>  extern const char *output_mov_long_double_arm_from_arm (rtx *);
>  extern const char *output_mov_double_fpa_from_arm (rtx *);
>  extern const char *output_mov_double_arm_from_fpa (rtx *);
> -extern const char *output_move_double (rtx *);
> +extern const char *output_move_double (rtx *, int, int *count);
>  extern const char *output_move_quad (rtx *);
> +extern int arm_count_output_move_double_insns (rtx *);
>  extern const char *output_move_vfp (rtx *operands);
>  extern const char *output_move_neon (rtx *operands);
>  extern int arm_attr_length_move_neon (rtx);
> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
> index 6cd80f8..446be81 100644
> --- a/gcc/config/arm/arm.c
> +++ b/gcc/config/arm/arm.c
> @@ -13262,11 +13262,24 @@ output_mov_double_arm_from_fpa (rtx *operands)
>  /* Output a move between double words.  It must be REG<-MEM
>     or MEM<-REG.  */
>  const char *
> -output_move_double (rtx *operands)
> +output_move_double (rtx *operands, int emit, int *count)
>  {
>    enum rtx_code code0 = GET_CODE (operands[0]);
>    enum rtx_code code1 = GET_CODE (operands[1]);
>    rtx otherops[3];
> +  if (count)
> +    *count = 1;
> +
> +  /* The only case when this might happen is when 
> +     you are looking at the length of a DImode instruction
> +     that has an invalid constant in it.  */
> +  if (code0 == REG && code1 != MEM)
> +    {
> +      gcc_assert (!emit);
> +      *count = 2;
> +      return "";
> +    }
> +      
>  
>    if (code0 == REG)
>      {
> @@ -13279,35 +13292,49 @@ output_move_double (rtx *operands)
>        switch (GET_CODE (XEXP (operands[1], 0)))
>  	{
>  	case REG:
> -	  if (TARGET_LDRD
> -	      && !(fix_cm3_ldrd && reg0 == REGNO(XEXP (operands[1], 0))))
> -	    output_asm_insn ("ldr%(d%)\t%0, [%m1]", operands);
> -	  else
> -	    output_asm_insn ("ldm%(ia%)\t%m1, %M0", operands);
> +
> +	  if (emit)
> +	    {
> +	      if (TARGET_LDRD
> +		  && !(fix_cm3_ldrd && reg0 == REGNO(XEXP (operands[1], 0))))
> +		output_asm_insn ("ldr%(d%)\t%0, [%m1]", operands);
> +	      else
> +		output_asm_insn ("ldm%(ia%)\t%m1, %M0", operands);
> +	    }
>  	  break;
>  
>  	case PRE_INC:
>  	  gcc_assert (TARGET_LDRD);
> -	  output_asm_insn ("ldr%(d%)\t%0, [%m1, #8]!", operands);
> +	  if (emit)
> +	    output_asm_insn ("ldr%(d%)\t%0, [%m1, #8]!", operands);
> +	  
>  	  break;
>  
>  	case PRE_DEC:
> -	  if (TARGET_LDRD)
> -	    output_asm_insn ("ldr%(d%)\t%0, [%m1, #-8]!", operands);
> -	  else
> -	    output_asm_insn ("ldm%(db%)\t%m1!, %M0", operands);
> +	  if (emit)
> +	    {
> +	      if (TARGET_LDRD)
> +		output_asm_insn ("ldr%(d%)\t%0, [%m1, #-8]!", operands);
> +	      else
> +		output_asm_insn ("ldm%(db%)\t%m1!, %M0", operands);
> +	    }
>  	  break;
>  
>  	case POST_INC:
> -	  if (TARGET_LDRD)
> -	    output_asm_insn ("ldr%(d%)\t%0, [%m1], #8", operands);
> -	  else
> -	    output_asm_insn ("ldm%(ia%)\t%m1!, %M0", operands);
> +	  
> +	  if (emit)
> +	    {
> +	      if (TARGET_LDRD)
> +		output_asm_insn ("ldr%(d%)\t%0, [%m1], #8", operands);
> +	      else
> +		output_asm_insn ("ldm%(ia%)\t%m1!, %M0", operands);
> +	    }
>  	  break;
>  
>  	case POST_DEC:
>  	  gcc_assert (TARGET_LDRD);
> -	  output_asm_insn ("ldr%(d%)\t%0, [%m1], #-8", operands);
> +	  if (emit)
> +	    output_asm_insn ("ldr%(d%)\t%0, [%m1], #-8", operands);
>  	  break;
>  
>  	case PRE_MODIFY:
> @@ -13325,8 +13352,13 @@ output_move_double (rtx *operands)
>  	      if (reg_overlap_mentioned_p (otherops[0], otherops[2]))
>  		{
>  		  /* Registers overlap so split out the increment.  */
> -		  output_asm_insn ("add%?\t%1, %1, %2", otherops);
> -		  output_asm_insn ("ldr%(d%)\t%0, [%1] @split", otherops);
> +		  if (emit)
> +		    {
> +		      output_asm_insn ("add%?\t%1, %1, %2", otherops);
> +		      output_asm_insn ("ldr%(d%)\t%0, [%1] @split", otherops);
> +		    }
> +		  if (count)
> +		    *count = 2;
>  		}
>  	      else
>  		{
> @@ -13337,11 +13369,20 @@ output_move_double (rtx *operands)
>  		      || GET_CODE (otherops[2]) != CONST_INT
>  		      || (INTVAL (otherops[2]) > -256
>  			  && INTVAL (otherops[2]) < 256))
> -		    output_asm_insn ("ldr%(d%)\t%0, [%1, %2]!", otherops);
> +		    {
> +		      if (emit)
> +			output_asm_insn ("ldr%(d%)\t%0, [%1, %2]!", otherops);
> +		    }
>  		  else
>  		    {
> -		      output_asm_insn ("ldr%?\t%0, [%1, %2]!", otherops);
> -		      output_asm_insn ("ldr%?\t%H0, [%1, #4]", otherops);
> +		      if (emit)
> +			{
> +			  output_asm_insn ("ldr%?\t%0, [%1, %2]!", otherops);
> +			  output_asm_insn ("ldr%?\t%H0, [%1, #4]", otherops);
> +			}
> +		      if (count)
> +			*count = 2;
> +
>  		    }
>  		}
>  	    }
> @@ -13354,11 +13395,19 @@ output_move_double (rtx *operands)
>  		  || GET_CODE (otherops[2]) != CONST_INT
>  		  || (INTVAL (otherops[2]) > -256
>  		      && INTVAL (otherops[2]) < 256))
> -		output_asm_insn ("ldr%(d%)\t%0, [%1], %2", otherops);
> +		{
> +		  if (emit)
> +		    output_asm_insn ("ldr%(d%)\t%0, [%1], %2", otherops);
> +		}
>  	      else
>  		{
> -		  output_asm_insn ("ldr%?\t%H0, [%1, #4]", otherops);
> -		  output_asm_insn ("ldr%?\t%0, [%1], %2", otherops);
> +		  if (emit)
> +		    {
> +		      output_asm_insn ("ldr%?\t%H0, [%1, #4]", otherops);
> +		      output_asm_insn ("ldr%?\t%0, [%1], %2", otherops);
> +		    }
> +		  if (count)
> +		    *count = 2;
>  		}
>  	    }
>  	  break;
> @@ -13371,12 +13420,19 @@ output_move_double (rtx *operands)
>  	  /* Use the second register of the pair to avoid problematic
>  	     overlap.  */
>  	  otherops[1] = operands[1];
> -	  output_asm_insn ("adr%?\t%0, %1", otherops);
> +	  if (emit)
> +	    output_asm_insn ("adr%?\t%0, %1", otherops);
>  	  operands[1] = otherops[0];
> -	  if (TARGET_LDRD)
> -	    output_asm_insn ("ldr%(d%)\t%0, [%1]", operands);
> -	  else
> -	    output_asm_insn ("ldm%(ia%)\t%1, %M0", operands);
> +	  if (emit)
> +	    {
> +	      if (TARGET_LDRD)
> +		output_asm_insn ("ldr%(d%)\t%0, [%1]", operands);
> +	      else
> +		output_asm_insn ("ldm%(ia%)\t%1, %M0", operands);
> +	    }
> +
> +	  if (count)
> +	    *count = 2;
>  	  break;
>  
>  	  /* ??? This needs checking for thumb2.  */
> @@ -13395,17 +13451,20 @@ output_move_double (rtx *operands)
>  		      switch ((int) INTVAL (otherops[2]))
>  			{
>  			case -8:
> -			  output_asm_insn ("ldm%(db%)\t%1, %M0", otherops);
> +			  if (emit)
> +			    output_asm_insn ("ldm%(db%)\t%1, %M0", otherops);
>  			  return "";
>  			case -4:
>  			  if (TARGET_THUMB2)
>  			    break;
> -			  output_asm_insn ("ldm%(da%)\t%1, %M0", otherops);
> +			  if (emit)
> +			    output_asm_insn ("ldm%(da%)\t%1, %M0", otherops);
>  			  return "";
>  			case 4:
>  			  if (TARGET_THUMB2)
>  			    break;
> -			  output_asm_insn ("ldm%(ib%)\t%1, %M0", otherops);
> +			  if (emit)
> +			    output_asm_insn ("ldm%(ib%)\t%1, %M0", otherops);
>  			  return "";
>  			}
>  		    }
> @@ -13433,34 +13492,50 @@ output_move_double (rtx *operands)
>  		      if (reg_overlap_mentioned_p (operands[0], otherops[2])
>  			  || (fix_cm3_ldrd && reg0 == REGNO (otherops[1])))
>  			{
> -			  output_asm_insn ("add%?\t%0, %1, %2", otherops);
> -			  output_asm_insn ("ldr%(d%)\t%0, [%1]", operands);
> +			  if (emit)
> +			    {
> +			      output_asm_insn ("add%?\t%0, %1, %2", otherops);
> +			      output_asm_insn ("ldr%(d%)\t%0, [%1]", operands);
> +			    }
> +			  if (count)
> +			    *count = 2;
>  			}
>  		      else
>  			{
>  			  otherops[0] = operands[0];
> -			  output_asm_insn ("ldr%(d%)\t%0, [%1, %2]", otherops);
> +			  if (emit)
> +			    output_asm_insn ("ldr%(d%)\t%0, [%1, %2]", otherops);
>  			}
>  		      return "";
>  		    }
>  
>  		  if (GET_CODE (otherops[2]) == CONST_INT)
> +		    {							
> +		      if (emit)
> +			{
> +			  if (!(const_ok_for_arm (INTVAL (otherops[2]))))
> +			    output_asm_insn ("sub%?\t%0, %1, #%n2", otherops);
> +			  else
> +			    output_asm_insn ("add%?\t%0, %1, %2", otherops);
> +			}
> +			
> +		    }
> +		  else
>  		    {
> -		      if (!(const_ok_for_arm (INTVAL (otherops[2]))))
> -			output_asm_insn ("sub%?\t%0, %1, #%n2", otherops);
> -		      else
> +		      if (emit)
>  			output_asm_insn ("add%?\t%0, %1, %2", otherops);
>  		    }
> -		  else
> -		    output_asm_insn ("add%?\t%0, %1, %2", otherops);
>  		}
>  	      else
> -		output_asm_insn ("sub%?\t%0, %1, %2", otherops);
> +		{
> +		  if (emit)
> +		    output_asm_insn ("sub%?\t%0, %1, %2", otherops);
> +		}
>  
>  	      if (TARGET_LDRD)
>  		return "ldr%(d%)\t%0, [%1]";
> -
> -	      return "ldm%(ia%)\t%1, %M0";
> +	      
> +		return "ldm%(ia%)\t%1, %M0";
>  	    }
>  	  else
>  	    {
> @@ -13468,13 +13543,24 @@ output_move_double (rtx *operands)
>  	      /* Take care of overlapping base/data reg.  */
>  	      if (reg_mentioned_p (operands[0], operands[1]))
>  		{
> -		  output_asm_insn ("ldr%?\t%0, %1", otherops);
> -		  output_asm_insn ("ldr%?\t%0, %1", operands);
> +		  if (emit)
> +		    {
> +		      output_asm_insn ("ldr%?\t%0, %1", otherops);
> +		      output_asm_insn ("ldr%?\t%0, %1", operands);
> +		    }
> +		  if (count)
> +		    *count = 2;
> +
>  		}
>  	      else
>  		{
> -		  output_asm_insn ("ldr%?\t%0, %1", operands);
> -		  output_asm_insn ("ldr%?\t%0, %1", otherops);
> +		  if (emit)
> +		    {
> +		      output_asm_insn ("ldr%?\t%0, %1", operands);
> +		      output_asm_insn ("ldr%?\t%0, %1", otherops);
> +		    }
> +		  if (count)
> +		    *count = 2;
>  		}
>  	    }
>  	}
> @@ -13488,34 +13574,45 @@ output_move_double (rtx *operands)
>        switch (GET_CODE (XEXP (operands[0], 0)))
>          {
>  	case REG:
> -	  if (TARGET_LDRD)
> -	    output_asm_insn ("str%(d%)\t%1, [%m0]", operands);
> -	  else
> -	    output_asm_insn ("stm%(ia%)\t%m0, %M1", operands);
> +	  if (emit)
> +	    {
> +	      if (TARGET_LDRD)
> +		output_asm_insn ("str%(d%)\t%1, [%m0]", operands);
> +	      else
> +		output_asm_insn ("stm%(ia%)\t%m0, %M1", operands);
> +	    }
>  	  break;
>  
>          case PRE_INC:
>  	  gcc_assert (TARGET_LDRD);
> -	  output_asm_insn ("str%(d%)\t%1, [%m0, #8]!", operands);
> +	  if (emit)
> +	    output_asm_insn ("str%(d%)\t%1, [%m0, #8]!", operands);
>  	  break;
>  
>          case PRE_DEC:
> -	  if (TARGET_LDRD)
> -	    output_asm_insn ("str%(d%)\t%1, [%m0, #-8]!", operands);
> -	  else
> -	    output_asm_insn ("stm%(db%)\t%m0!, %M1", operands);
> +	  if (emit)
> +	    {
> +	      if (TARGET_LDRD)
> +		output_asm_insn ("str%(d%)\t%1, [%m0, #-8]!", operands);
> +	      else
> +		output_asm_insn ("stm%(db%)\t%m0!, %M1", operands);
> +	    }
>  	  break;
>  
>          case POST_INC:
> -	  if (TARGET_LDRD)
> -	    output_asm_insn ("str%(d%)\t%1, [%m0], #8", operands);
> -	  else
> -	    output_asm_insn ("stm%(ia%)\t%m0!, %M1", operands);
> +	  if (emit)
> +	    {
> +	      if (TARGET_LDRD)
> +		output_asm_insn ("str%(d%)\t%1, [%m0], #8", operands);
> +	      else
> +		output_asm_insn ("stm%(ia%)\t%m0!, %M1", operands);
> +	    }
>  	  break;
>  
>          case POST_DEC:
>  	  gcc_assert (TARGET_LDRD);
> -	  output_asm_insn ("str%(d%)\t%1, [%m0], #-8", operands);
> +	  if (emit)
> +	    output_asm_insn ("str%(d%)\t%1, [%m0], #-8", operands);
>  	  break;
>  
>  	case PRE_MODIFY:
> @@ -13533,19 +13630,35 @@ output_move_double (rtx *operands)
>  	    {
>  	      if (GET_CODE (XEXP (operands[0], 0)) == PRE_MODIFY)
>  		{
> -		  output_asm_insn ("str%?\t%0, [%1, %2]!", otherops);
> -		  output_asm_insn ("str%?\t%H0, [%1, #4]", otherops);
> +		  if (emit)
> +		    {
> +		      output_asm_insn ("str%?\t%0, [%1, %2]!", otherops);
> +		      output_asm_insn ("str%?\t%H0, [%1, #4]", otherops);
> +		    }
> +		  if (count)
> +		    *count = 2;
>  		}
>  	      else
>  		{
> -		  output_asm_insn ("str%?\t%H0, [%1, #4]", otherops);
> -		  output_asm_insn ("str%?\t%0, [%1], %2", otherops);
> +		  if (emit)
> +		    {
> +		      output_asm_insn ("str%?\t%H0, [%1, #4]", otherops);
> +		      output_asm_insn ("str%?\t%0, [%1], %2", otherops);
> +		    }
> +		  if (count)
> +		    *count = 2;
>  		}
>  	    }
>  	  else if (GET_CODE (XEXP (operands[0], 0)) == PRE_MODIFY)
> -	    output_asm_insn ("str%(d%)\t%0, [%1, %2]!", otherops);
> +	    {
> +	      if (emit)
> +		output_asm_insn ("str%(d%)\t%0, [%1, %2]!", otherops);
> +	    }
>  	  else
> -	    output_asm_insn ("str%(d%)\t%0, [%1], %2", otherops);
> +	    {
> +	      if (emit)
> +		output_asm_insn ("str%(d%)\t%0, [%1], %2", otherops);
> +	    }
>  	  break;
>  
>  	case PLUS:
> @@ -13555,19 +13668,22 @@ output_move_double (rtx *operands)
>  	      switch ((int) INTVAL (XEXP (XEXP (operands[0], 0), 1)))
>  		{
>  		case -8:
> -		  output_asm_insn ("stm%(db%)\t%m0, %M1", operands);
> +		  if (emit)
> +		    output_asm_insn ("stm%(db%)\t%m0, %M1", operands);
>  		  return "";
>  
>  		case -4:
>  		  if (TARGET_THUMB2)
>  		    break;
> -		  output_asm_insn ("stm%(da%)\t%m0, %M1", operands);
> +		  if (emit)
> +		    output_asm_insn ("stm%(da%)\t%m0, %M1", operands);
>  		  return "";
>  
>  		case 4:
>  		  if (TARGET_THUMB2)
>  		    break;
> -		  output_asm_insn ("stm%(ib%)\t%m0, %M1", operands);
> +		  if (emit)
> +		    output_asm_insn ("stm%(ib%)\t%m0, %M1", operands);
>  		  return "";
>  		}
>  	    }
> @@ -13580,7 +13696,8 @@ output_move_double (rtx *operands)
>  	    {
>  	      otherops[0] = operands[1];
>  	      otherops[1] = XEXP (XEXP (operands[0], 0), 0);
> -	      output_asm_insn ("str%(d%)\t%0, [%1, %2]", otherops);
> +	      if (emit)
> +		output_asm_insn ("str%(d%)\t%0, [%1, %2]", otherops);
>  	      return "";
>  	    }
>  	  /* Fall through */
> @@ -13588,8 +13705,14 @@ output_move_double (rtx *operands)
>          default:
>  	  otherops[0] = adjust_address (operands[0], SImode, 4);
>  	  otherops[1] = operands[1];
> -	  output_asm_insn ("str%?\t%1, %0", operands);
> -	  output_asm_insn ("str%?\t%H1, %0", otherops);
> +	  if (emit)
> +	    {
> +	      output_asm_insn ("str%?\t%1, %0", operands);
> +	      output_asm_insn ("str%?\t%H1, %0", otherops);
> +	    }
> +	  if (count)
> +	    *count = 2;
> +
>  	}
>      }
>  
> @@ -24183,4 +24306,13 @@ arm_attr_length_push_multi(rtx parallel_op, rtx first_op)
>    return 4;
>  }
>  
> +/* Compute the number of instructions emitted by output_move_double.  */
> +int
> +arm_count_output_move_double_insns (rtx *operands)
> +{
> +  int count;
> +  output_move_double (operands, 0, &count);
> +  return count;
> +}
> +
>  #include "gt-arm.h"
> diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
> index 3d4dcfa..082ded4 100644
> --- a/gcc/config/arm/arm.md
> +++ b/gcc/config/arm/arm.md
> @@ -4981,7 +4981,7 @@
>      case 2:
>        return \"#\";
>      default:
> -      return output_move_double (operands);
> +      return output_move_double (operands, 1, NULL);
>      }
>    "
>    [(set_attr "length" "8,12,16,8,8")
> @@ -6341,7 +6341,7 @@
>      case 2:
>        return \"#\";
>      default:
> -      return output_move_double (operands);
> +      return output_move_double (operands, 1, NULL);
>      }
>    "
>    [(set_attr "length" "8,12,16,8,8")
> @@ -10315,6 +10315,7 @@
>    [(set (match_operand:SI 0 "s_register_operand" "=r,r")
>  	(if_then_else:SI (match_operator 4 "arm_comparison_operator"
>  			  [(match_operand 3 "cc_register" "") (const_int 0)])
> +
>  			 (match_operand:SI 1 "arm_rhs_operand" "0,?rI")
>  			 (not:SI
>  			  (match_operand:SI 2 "s_register_operand" "r,r"))))]
> diff --git a/gcc/config/arm/cirrus.md b/gcc/config/arm/cirrus.md
> index f08da0b..e3fe687 100644
> --- a/gcc/config/arm/cirrus.md
> +++ b/gcc/config/arm/cirrus.md
> @@ -1,4 +1,4 @@
> -;; Cirrus EP9312 "Maverick" ARM floating point co-processor description.
> +;; CIRRUS EP9312 "Maverick" ARM floating point co-processor description.
>  ;; Copyright (C) 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
>  ;; Contributed by Red Hat.
>  ;; Written by Aldy Hernandez (aldyh@redhat.com)
> @@ -379,7 +379,7 @@
>        return \"#\";
>      case 1:
>      case 2:
> -      return output_move_double (operands);
> +      return output_move_double (operands, 1, NULL);
>  
>      case 3: return \"cfmv64lr%?\\t%V0, %Q1\;cfmv64hr%?\\t%V0, %R1\";
>      case 4: return \"cfmvr64l%?\\t%Q0, %V1\;cfmvr64h%?\\t%R0, %V1\";
> @@ -439,7 +439,7 @@
>      case 0: return \"ldm%?ia\\t%m1, %M0\\t%@ double\";
>      case 1: return \"stm%?ia\\t%m0, %M1\\t%@ double\";
>      case 2: return \"#\";
> -    case 3: case 4: return output_move_double (operands);
> +    case 3: case 4: return output_move_double (operands, 1, NULL);
>      case 5: return \"cfcpyd%?\\t%V0, %V1\";
>      case 6: return \"cfldrd%?\\t%V0, %1\";
>      case 7: return \"cfmvdlr\\t%V0, %Q1\;cfmvdhr%?\\t%V0, %R1\";
> @@ -466,7 +466,7 @@
>      case 0:
>      case 1:
>      case 2:
> -      return (output_move_double (operands));
> +      return (output_move_double (operands, 1, NULL));
>  
>      case 3: return \"cfmv64lr%?\\t%V0, %Q1\;cfmv64hr%?\\t%V0, %R1\";
>      case 4: return \"cfmvr64l%?\\t%Q0, %V1\;cfmvr64h%?\\t%R0, %V1\";
> @@ -522,7 +522,7 @@
>      {
>      case 0: return \"ldm%?ia\\t%m1, %M0\\t%@ double\";
>      case 1: return \"stm%?ia\\t%m0, %M1\\t%@ double\";
> -    case 2: case 3: case 4: return output_move_double (operands);
> +    case 2: case 3: case 4: return output_move_double (operands, 1, NULL);
>      case 5: return \"cfcpyd%?\\t%V0, %V1\";
>      case 6: return \"cfldrd%?\\t%V0, %1\";
>      case 7: return \"cfmvdlr\\t%V0, %Q1\;cfmvdhr%?\\t%V0, %R1\";
> diff --git a/gcc/config/arm/fpa.md b/gcc/config/arm/fpa.md
> index 6e6dd8d..3d41950 100644
> --- a/gcc/config/arm/fpa.md
> +++ b/gcc/config/arm/fpa.md
> @@ -567,7 +567,7 @@
>      case 0: return \"ldm%(ia%)\\t%m1, %M0\\t%@ double\";
>      case 1: return \"stm%(ia%)\\t%m0, %M1\\t%@ double\";
>      case 2: return \"#\";
> -    case 3: case 4: return output_move_double (operands);
> +    case 3: case 4: return output_move_double (operands, 1, NULL);
>      case 5: return \"mvf%?d\\t%0, %1\";
>      case 6: return \"mnf%?d\\t%0, #%N1\";
>      case 7: return \"ldf%?d\\t%0, %1\";
> @@ -657,7 +657,7 @@
>      default:
>      case 0: return \"ldm%(ia%)\\t%m1, %M0\\t%@ double\";
>      case 1: return \"stm%(ia%)\\t%m0, %M1\\t%@ double\";
> -    case 2: case 3: case 4: return output_move_double (operands);
> +    case 2: case 3: case 4: return output_move_double (operands, 1, NULL);
>      case 5: return \"mvf%?d\\t%0, %1\";
>      case 6: return \"mnf%?d\\t%0, #%N1\";
>      case 7: return \"ldf%?d\\t%0, %1\";
> diff --git a/gcc/config/arm/iwmmxt.md b/gcc/config/arm/iwmmxt.md
> index 7f13ae4..b066157 100644
> --- a/gcc/config/arm/iwmmxt.md
> +++ b/gcc/config/arm/iwmmxt.md
> @@ -76,7 +76,7 @@
>    switch (which_alternative)
>      {
>      default:
> -      return output_move_double (operands);
> +      return output_move_double (operands, 1, NULL);
>      case 0:
>        return \"#\";
>      case 3:
> @@ -173,7 +173,7 @@
>     case 3: return \"tmrrc%?\\t%Q0, %R0, %1\";
>     case 4: return \"tmcrr%?\\t%0, %Q1, %R1\";
>     case 5: return \"#\";
> -   default: return output_move_double (operands);
> +   default: return output_move_double (operands, 1, NULL);
>     }"
>    [(set_attr "predicable" "yes")
>     (set_attr "length"         "4,     4,   4,4,4,8,   8,8")
> diff --git a/gcc/config/arm/neon.md b/gcc/config/arm/neon.md
> index 1f9ea67..6d61233 100644
> --- a/gcc/config/arm/neon.md
> +++ b/gcc/config/arm/neon.md
> @@ -190,7 +190,7 @@
>      case 2: gcc_unreachable ();
>      case 4: return "vmov\t%Q0, %R0, %P1  @ <mode>";
>      case 5: return "vmov\t%P0, %Q1, %R1  @ <mode>";
> -    default: return output_move_double (operands);
> +    default: return output_move_double (operands, 1, NULL);
>      }
>  }
>   [(set_attr "neon_type" "neon_int_1,*,neon_vmov,*,neon_mrrc,neon_mcr_2_mcrr,*,*,*")
> diff --git a/gcc/config/arm/vfp.md b/gcc/config/arm/vfp.md
> index 3311ae0..82f96f0 100644
> --- a/gcc/config/arm/vfp.md
> +++ b/gcc/config/arm/vfp.md
> @@ -150,7 +150,7 @@
>      case 4:
>      case 5:
>      case 6:
> -      return output_move_double (operands);
> +      return output_move_double (operands, 1, NULL);
>      case 7:
>        return \"fmdrr%?\\t%P0, %Q1, %R1\\t%@ int\";
>      case 8:
> @@ -199,7 +199,7 @@
>      case 4:
>      case 5:
>      case 6:
> -      return output_move_double (operands);
> +      return output_move_double (operands, 1, NULL);
>      case 7:
>        return \"fmdrr%?\\t%P0, %Q1, %R1\\t%@ int\";
>      case 8:
> @@ -213,10 +213,19 @@
>      }
>    "
>    [(set_attr "type" "*,*,*,*,load2,load2,store2,r_2_f,f_2_r,ffarithd,f_loadd,f_stored")
> -   (set_attr "length" "4,8,12,16,8,8,8,4,4,4,4,4")
> +   (set (attr "length") (cond [(eq_attr "alternative" "1") (const_int 8)
> +                               (eq_attr "alternative" "2") (const_int 12)
> +                               (eq_attr "alternative" "3") (const_int 16)
> +                               (eq_attr "alternative" "4,5,6") 
> +			       (symbol_ref 
> +				"arm_count_output_move_double_insns (operands) \
> +                                 * 4")]
> +                              (const_int 4)))
>     (set_attr "predicable"    "yes")
>     (set_attr "pool_range"     "*,*,*,*,1020,4096,*,*,*,*,1020,*")
>     (set_attr "neg_pool_range" "*,*,*,*,1008,0,*,*,*,*,1008,*")
> +   (set (attr "ce_count") 
> +	(symbol_ref "arm_count_output_move_double_insns (operands)"))
>     (set_attr "arch"           "t2,any,any,any,a,t2,any,any,any,any,any,any")]
>   )
>  
> @@ -427,7 +436,7 @@
>        case 3: case 4:
>  	return output_move_vfp (operands);
>        case 5: case 6:
> -	return output_move_double (operands);
> +	return output_move_double (operands, 1, NULL);
>        case 7:
>  	if (TARGET_VFP_SINGLE)
>  	  return \"fcpys%?\\t%0, %1\;fcpys%?\\t%p0, %p1\";
> @@ -473,7 +482,7 @@
>        case 3: case 4:
>  	return output_move_vfp (operands);
>        case 5: case 6: case 8:
> -	return output_move_double (operands);
> +	return output_move_double (operands, 1, NULL);
>        case 7:
>  	if (TARGET_VFP_SINGLE)
>  	  return \"fcpys%?\\t%0, %1\;fcpys%?\\t%p0, %p1\";

Patch

diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 2f7c508..d99d1ce 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -131,8 +131,9 @@  extern const char *output_mov_long_double_arm_from_fpa (rtx *);
 extern const char *output_mov_long_double_arm_from_arm (rtx *);
 extern const char *output_mov_double_fpa_from_arm (rtx *);
 extern const char *output_mov_double_arm_from_fpa (rtx *);
-extern const char *output_move_double (rtx *);
+extern const char *output_move_double (rtx *, int, int *count);
 extern const char *output_move_quad (rtx *);
+extern int arm_count_output_move_double_insns (rtx *);
 extern const char *output_move_vfp (rtx *operands);
 extern const char *output_move_neon (rtx *operands);
 extern int arm_attr_length_move_neon (rtx);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 6cd80f8..446be81 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -13262,11 +13262,24 @@  output_mov_double_arm_from_fpa (rtx *operands)
 /* Output a move between double words.  It must be REG<-MEM
    or MEM<-REG.  */
 const char *
-output_move_double (rtx *operands)
+output_move_double (rtx *operands, int emit, int *count)
 {
   enum rtx_code code0 = GET_CODE (operands[0]);
   enum rtx_code code1 = GET_CODE (operands[1]);
   rtx otherops[3];
+  if (count)
+    *count = 1;
+
+  /* The only case when this might happen is when 
+     you are looking at the length of a DImode instruction
+     that has an invalid constant in it.  */
+  if (code0 == REG && code1 != MEM)
+    {
+      gcc_assert (!emit);
+      *count = 2;
+      return "";
+    }
+      
 
   if (code0 == REG)
     {
@@ -13279,35 +13292,49 @@  output_move_double (rtx *operands)
       switch (GET_CODE (XEXP (operands[1], 0)))
 	{
 	case REG:
-	  if (TARGET_LDRD
-	      && !(fix_cm3_ldrd && reg0 == REGNO(XEXP (operands[1], 0))))
-	    output_asm_insn ("ldr%(d%)\t%0, [%m1]", operands);
-	  else
-	    output_asm_insn ("ldm%(ia%)\t%m1, %M0", operands);
+
+	  if (emit)
+	    {
+	      if (TARGET_LDRD
+		  && !(fix_cm3_ldrd && reg0 == REGNO(XEXP (operands[1], 0))))
+		output_asm_insn ("ldr%(d%)\t%0, [%m1]", operands);
+	      else
+		output_asm_insn ("ldm%(ia%)\t%m1, %M0", operands);
+	    }
 	  break;
 
 	case PRE_INC:
 	  gcc_assert (TARGET_LDRD);
-	  output_asm_insn ("ldr%(d%)\t%0, [%m1, #8]!", operands);
+	  if (emit)
+	    output_asm_insn ("ldr%(d%)\t%0, [%m1, #8]!", operands);
+	  
 	  break;
 
 	case PRE_DEC:
-	  if (TARGET_LDRD)
-	    output_asm_insn ("ldr%(d%)\t%0, [%m1, #-8]!", operands);
-	  else
-	    output_asm_insn ("ldm%(db%)\t%m1!, %M0", operands);
+	  if (emit)
+	    {
+	      if (TARGET_LDRD)
+		output_asm_insn ("ldr%(d%)\t%0, [%m1, #-8]!", operands);
+	      else
+		output_asm_insn ("ldm%(db%)\t%m1!, %M0", operands);
+	    }
 	  break;
 
 	case POST_INC:
-	  if (TARGET_LDRD)
-	    output_asm_insn ("ldr%(d%)\t%0, [%m1], #8", operands);
-	  else
-	    output_asm_insn ("ldm%(ia%)\t%m1!, %M0", operands);
+	  
+	  if (emit)
+	    {
+	      if (TARGET_LDRD)
+		output_asm_insn ("ldr%(d%)\t%0, [%m1], #8", operands);
+	      else
+		output_asm_insn ("ldm%(ia%)\t%m1!, %M0", operands);
+	    }
 	  break;
 
 	case POST_DEC:
 	  gcc_assert (TARGET_LDRD);
-	  output_asm_insn ("ldr%(d%)\t%0, [%m1], #-8", operands);
+	  if (emit)
+	    output_asm_insn ("ldr%(d%)\t%0, [%m1], #-8", operands);
 	  break;
 
 	case PRE_MODIFY:
@@ -13325,8 +13352,13 @@  output_move_double (rtx *operands)
 	      if (reg_overlap_mentioned_p (otherops[0], otherops[2]))
 		{
 		  /* Registers overlap so split out the increment.  */
-		  output_asm_insn ("add%?\t%1, %1, %2", otherops);
-		  output_asm_insn ("ldr%(d%)\t%0, [%1] @split", otherops);
+		  if (emit)
+		    {
+		      output_asm_insn ("add%?\t%1, %1, %2", otherops);
+		      output_asm_insn ("ldr%(d%)\t%0, [%1] @split", otherops);
+		    }
+		  if (count)
+		    *count = 2;
 		}
 	      else
 		{
@@ -13337,11 +13369,20 @@  output_move_double (rtx *operands)
 		      || GET_CODE (otherops[2]) != CONST_INT
 		      || (INTVAL (otherops[2]) > -256
 			  && INTVAL (otherops[2]) < 256))
-		    output_asm_insn ("ldr%(d%)\t%0, [%1, %2]!", otherops);
+		    {
+		      if (emit)
+			output_asm_insn ("ldr%(d%)\t%0, [%1, %2]!", otherops);
+		    }
 		  else
 		    {
-		      output_asm_insn ("ldr%?\t%0, [%1, %2]!", otherops);
-		      output_asm_insn ("ldr%?\t%H0, [%1, #4]", otherops);
+		      if (emit)
+			{
+			  output_asm_insn ("ldr%?\t%0, [%1, %2]!", otherops);
+			  output_asm_insn ("ldr%?\t%H0, [%1, #4]", otherops);
+			}
+		      if (count)
+			*count = 2;
+
 		    }
 		}
 	    }
@@ -13354,11 +13395,19 @@  output_move_double (rtx *operands)
 		  || GET_CODE (otherops[2]) != CONST_INT
 		  || (INTVAL (otherops[2]) > -256
 		      && INTVAL (otherops[2]) < 256))
-		output_asm_insn ("ldr%(d%)\t%0, [%1], %2", otherops);
+		{
+		  if (emit)
+		    output_asm_insn ("ldr%(d%)\t%0, [%1], %2", otherops);
+		}
 	      else
 		{
-		  output_asm_insn ("ldr%?\t%H0, [%1, #4]", otherops);
-		  output_asm_insn ("ldr%?\t%0, [%1], %2", otherops);
+		  if (emit)
+		    {
+		      output_asm_insn ("ldr%?\t%H0, [%1, #4]", otherops);
+		      output_asm_insn ("ldr%?\t%0, [%1], %2", otherops);
+		    }
+		  if (count)
+		    *count = 2;
 		}
 	    }
 	  break;
@@ -13371,12 +13420,19 @@  output_move_double (rtx *operands)
 	  /* Use the second register of the pair to avoid problematic
 	     overlap.  */
 	  otherops[1] = operands[1];
-	  output_asm_insn ("adr%?\t%0, %1", otherops);
+	  if (emit)
+	    output_asm_insn ("adr%?\t%0, %1", otherops);
 	  operands[1] = otherops[0];
-	  if (TARGET_LDRD)
-	    output_asm_insn ("ldr%(d%)\t%0, [%1]", operands);
-	  else
-	    output_asm_insn ("ldm%(ia%)\t%1, %M0", operands);
+	  if (emit)
+	    {
+	      if (TARGET_LDRD)
+		output_asm_insn ("ldr%(d%)\t%0, [%1]", operands);
+	      else
+		output_asm_insn ("ldm%(ia%)\t%1, %M0", operands);
+	    }
+
+	  if (count)
+	    *count = 2;
 	  break;
 
 	  /* ??? This needs checking for thumb2.  */
@@ -13395,17 +13451,20 @@  output_move_double (rtx *operands)
 		      switch ((int) INTVAL (otherops[2]))
 			{
 			case -8:
-			  output_asm_insn ("ldm%(db%)\t%1, %M0", otherops);
+			  if (emit)
+			    output_asm_insn ("ldm%(db%)\t%1, %M0", otherops);
 			  return "";
 			case -4:
 			  if (TARGET_THUMB2)
 			    break;
-			  output_asm_insn ("ldm%(da%)\t%1, %M0", otherops);
+			  if (emit)
+			    output_asm_insn ("ldm%(da%)\t%1, %M0", otherops);
 			  return "";
 			case 4:
 			  if (TARGET_THUMB2)
 			    break;
-			  output_asm_insn ("ldm%(ib%)\t%1, %M0", otherops);
+			  if (emit)
+			    output_asm_insn ("ldm%(ib%)\t%1, %M0", otherops);
 			  return "";
 			}
 		    }
@@ -13433,34 +13492,50 @@  output_move_double (rtx *operands)
 		      if (reg_overlap_mentioned_p (operands[0], otherops[2])
 			  || (fix_cm3_ldrd && reg0 == REGNO (otherops[1])))
 			{
-			  output_asm_insn ("add%?\t%0, %1, %2", otherops);
-			  output_asm_insn ("ldr%(d%)\t%0, [%1]", operands);
+			  if (emit)
+			    {
+			      output_asm_insn ("add%?\t%0, %1, %2", otherops);
+			      output_asm_insn ("ldr%(d%)\t%0, [%1]", operands);
+			    }
+			  if (count)
+			    *count = 2;
 			}
 		      else
 			{
 			  otherops[0] = operands[0];
-			  output_asm_insn ("ldr%(d%)\t%0, [%1, %2]", otherops);
+			  if (emit)
+			    output_asm_insn ("ldr%(d%)\t%0, [%1, %2]", otherops);
 			}
 		      return "";
 		    }
 
 		  if (GET_CODE (otherops[2]) == CONST_INT)
+		    {							
+		      if (emit)
+			{
+			  if (!(const_ok_for_arm (INTVAL (otherops[2]))))
+			    output_asm_insn ("sub%?\t%0, %1, #%n2", otherops);
+			  else
+			    output_asm_insn ("add%?\t%0, %1, %2", otherops);
+			}
+			
+		    }
+		  else
 		    {
-		      if (!(const_ok_for_arm (INTVAL (otherops[2]))))
-			output_asm_insn ("sub%?\t%0, %1, #%n2", otherops);
-		      else
+		      if (emit)
 			output_asm_insn ("add%?\t%0, %1, %2", otherops);
 		    }
-		  else
-		    output_asm_insn ("add%?\t%0, %1, %2", otherops);
 		}
 	      else
-		output_asm_insn ("sub%?\t%0, %1, %2", otherops);
+		{
+		  if (emit)
+		    output_asm_insn ("sub%?\t%0, %1, %2", otherops);
+		}
 
 	      if (TARGET_LDRD)
 		return "ldr%(d%)\t%0, [%1]";
-
-	      return "ldm%(ia%)\t%1, %M0";
+	      
+		return "ldm%(ia%)\t%1, %M0";
 	    }
 	  else
 	    {
@@ -13468,13 +13543,24 @@  output_move_double (rtx *operands)
 	      /* Take care of overlapping base/data reg.  */
 	      if (reg_mentioned_p (operands[0], operands[1]))
 		{
-		  output_asm_insn ("ldr%?\t%0, %1", otherops);
-		  output_asm_insn ("ldr%?\t%0, %1", operands);
+		  if (emit)
+		    {
+		      output_asm_insn ("ldr%?\t%0, %1", otherops);
+		      output_asm_insn ("ldr%?\t%0, %1", operands);
+		    }
+		  if (count)
+		    *count = 2;
+
 		}
 	      else
 		{
-		  output_asm_insn ("ldr%?\t%0, %1", operands);
-		  output_asm_insn ("ldr%?\t%0, %1", otherops);
+		  if (emit)
+		    {
+		      output_asm_insn ("ldr%?\t%0, %1", operands);
+		      output_asm_insn ("ldr%?\t%0, %1", otherops);
+		    }
+		  if (count)
+		    *count = 2;
 		}
 	    }
 	}
@@ -13488,34 +13574,45 @@  output_move_double (rtx *operands)
       switch (GET_CODE (XEXP (operands[0], 0)))
         {
 	case REG:
-	  if (TARGET_LDRD)
-	    output_asm_insn ("str%(d%)\t%1, [%m0]", operands);
-	  else
-	    output_asm_insn ("stm%(ia%)\t%m0, %M1", operands);
+	  if (emit)
+	    {
+	      if (TARGET_LDRD)
+		output_asm_insn ("str%(d%)\t%1, [%m0]", operands);
+	      else
+		output_asm_insn ("stm%(ia%)\t%m0, %M1", operands);
+	    }
 	  break;
 
         case PRE_INC:
 	  gcc_assert (TARGET_LDRD);
-	  output_asm_insn ("str%(d%)\t%1, [%m0, #8]!", operands);
+	  if (emit)
+	    output_asm_insn ("str%(d%)\t%1, [%m0, #8]!", operands);
 	  break;
 
         case PRE_DEC:
-	  if (TARGET_LDRD)
-	    output_asm_insn ("str%(d%)\t%1, [%m0, #-8]!", operands);
-	  else
-	    output_asm_insn ("stm%(db%)\t%m0!, %M1", operands);
+	  if (emit)
+	    {
+	      if (TARGET_LDRD)
+		output_asm_insn ("str%(d%)\t%1, [%m0, #-8]!", operands);
+	      else
+		output_asm_insn ("stm%(db%)\t%m0!, %M1", operands);
+	    }
 	  break;
 
         case POST_INC:
-	  if (TARGET_LDRD)
-	    output_asm_insn ("str%(d%)\t%1, [%m0], #8", operands);
-	  else
-	    output_asm_insn ("stm%(ia%)\t%m0!, %M1", operands);
+	  if (emit)
+	    {
+	      if (TARGET_LDRD)
+		output_asm_insn ("str%(d%)\t%1, [%m0], #8", operands);
+	      else
+		output_asm_insn ("stm%(ia%)\t%m0!, %M1", operands);
+	    }
 	  break;
 
         case POST_DEC:
 	  gcc_assert (TARGET_LDRD);
-	  output_asm_insn ("str%(d%)\t%1, [%m0], #-8", operands);
+	  if (emit)
+	    output_asm_insn ("str%(d%)\t%1, [%m0], #-8", operands);
 	  break;
 
 	case PRE_MODIFY:
@@ -13533,19 +13630,35 @@  output_move_double (rtx *operands)
 	    {
 	      if (GET_CODE (XEXP (operands[0], 0)) == PRE_MODIFY)
 		{
-		  output_asm_insn ("str%?\t%0, [%1, %2]!", otherops);
-		  output_asm_insn ("str%?\t%H0, [%1, #4]", otherops);
+		  if (emit)
+		    {
+		      output_asm_insn ("str%?\t%0, [%1, %2]!", otherops);
+		      output_asm_insn ("str%?\t%H0, [%1, #4]", otherops);
+		    }
+		  if (count)
+		    *count = 2;
 		}
 	      else
 		{
-		  output_asm_insn ("str%?\t%H0, [%1, #4]", otherops);
-		  output_asm_insn ("str%?\t%0, [%1], %2", otherops);
+		  if (emit)
+		    {
+		      output_asm_insn ("str%?\t%H0, [%1, #4]", otherops);
+		      output_asm_insn ("str%?\t%0, [%1], %2", otherops);
+		    }
+		  if (count)
+		    *count = 2;
 		}
 	    }
 	  else if (GET_CODE (XEXP (operands[0], 0)) == PRE_MODIFY)
-	    output_asm_insn ("str%(d%)\t%0, [%1, %2]!", otherops);
+	    {
+	      if (emit)
+		output_asm_insn ("str%(d%)\t%0, [%1, %2]!", otherops);
+	    }
 	  else
-	    output_asm_insn ("str%(d%)\t%0, [%1], %2", otherops);
+	    {
+	      if (emit)
+		output_asm_insn ("str%(d%)\t%0, [%1], %2", otherops);
+	    }
 	  break;
 
 	case PLUS:
@@ -13555,19 +13668,22 @@  output_move_double (rtx *operands)
 	      switch ((int) INTVAL (XEXP (XEXP (operands[0], 0), 1)))
 		{
 		case -8:
-		  output_asm_insn ("stm%(db%)\t%m0, %M1", operands);
+		  if (emit)
+		    output_asm_insn ("stm%(db%)\t%m0, %M1", operands);
 		  return "";
 
 		case -4:
 		  if (TARGET_THUMB2)
 		    break;
-		  output_asm_insn ("stm%(da%)\t%m0, %M1", operands);
+		  if (emit)
+		    output_asm_insn ("stm%(da%)\t%m0, %M1", operands);
 		  return "";
 
 		case 4:
 		  if (TARGET_THUMB2)
 		    break;
-		  output_asm_insn ("stm%(ib%)\t%m0, %M1", operands);
+		  if (emit)
+		    output_asm_insn ("stm%(ib%)\t%m0, %M1", operands);
 		  return "";
 		}
 	    }
@@ -13580,7 +13696,8 @@  output_move_double (rtx *operands)
 	    {
 	      otherops[0] = operands[1];
 	      otherops[1] = XEXP (XEXP (operands[0], 0), 0);
-	      output_asm_insn ("str%(d%)\t%0, [%1, %2]", otherops);
+	      if (emit)
+		output_asm_insn ("str%(d%)\t%0, [%1, %2]", otherops);
 	      return "";
 	    }
 	  /* Fall through */
@@ -13588,8 +13705,14 @@  output_move_double (rtx *operands)
         default:
 	  otherops[0] = adjust_address (operands[0], SImode, 4);
 	  otherops[1] = operands[1];
-	  output_asm_insn ("str%?\t%1, %0", operands);
-	  output_asm_insn ("str%?\t%H1, %0", otherops);
+	  if (emit)
+	    {
+	      output_asm_insn ("str%?\t%1, %0", operands);
+	      output_asm_insn ("str%?\t%H1, %0", otherops);
+	    }
+	  if (count)
+	    *count = 2;
+
 	}
     }
 
@@ -24183,4 +24306,13 @@  arm_attr_length_push_multi(rtx parallel_op, rtx first_op)
   return 4;
 }
 
+/* Compute the number of instructions emitted by output_move_double.  */
+int
+arm_count_output_move_double_insns (rtx *operands)
+{
+  int count;
+  output_move_double (operands, 0, &count);
+  return count;
+}
+
 #include "gt-arm.h"
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 3d4dcfa..082ded4 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -4981,7 +4981,7 @@ 
     case 2:
       return \"#\";
     default:
-      return output_move_double (operands);
+      return output_move_double (operands, 1, NULL);
     }
   "
   [(set_attr "length" "8,12,16,8,8")
@@ -6341,7 +6341,7 @@ 
     case 2:
       return \"#\";
     default:
-      return output_move_double (operands);
+      return output_move_double (operands, 1, NULL);
     }
   "
   [(set_attr "length" "8,12,16,8,8")
@@ -10315,6 +10315,7 @@ 
   [(set (match_operand:SI 0 "s_register_operand" "=r,r")
 	(if_then_else:SI (match_operator 4 "arm_comparison_operator"
 			  [(match_operand 3 "cc_register" "") (const_int 0)])
+
 			 (match_operand:SI 1 "arm_rhs_operand" "0,?rI")
 			 (not:SI
 			  (match_operand:SI 2 "s_register_operand" "r,r"))))]
diff --git a/gcc/config/arm/cirrus.md b/gcc/config/arm/cirrus.md
index f08da0b..e3fe687 100644
--- a/gcc/config/arm/cirrus.md
+++ b/gcc/config/arm/cirrus.md
@@ -1,4 +1,4 @@ 
-;; Cirrus EP9312 "Maverick" ARM floating point co-processor description.
+;; CIRRUS EP9312 "Maverick" ARM floating point co-processor description.
 ;; Copyright (C) 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
 ;; Contributed by Red Hat.
 ;; Written by Aldy Hernandez (aldyh@redhat.com)
@@ -379,7 +379,7 @@ 
       return \"#\";
     case 1:
     case 2:
-      return output_move_double (operands);
+      return output_move_double (operands, 1, NULL);
 
     case 3: return \"cfmv64lr%?\\t%V0, %Q1\;cfmv64hr%?\\t%V0, %R1\";
     case 4: return \"cfmvr64l%?\\t%Q0, %V1\;cfmvr64h%?\\t%R0, %V1\";
@@ -439,7 +439,7 @@ 
     case 0: return \"ldm%?ia\\t%m1, %M0\\t%@ double\";
     case 1: return \"stm%?ia\\t%m0, %M1\\t%@ double\";
     case 2: return \"#\";
-    case 3: case 4: return output_move_double (operands);
+    case 3: case 4: return output_move_double (operands, 1, NULL);
     case 5: return \"cfcpyd%?\\t%V0, %V1\";
     case 6: return \"cfldrd%?\\t%V0, %1\";
     case 7: return \"cfmvdlr\\t%V0, %Q1\;cfmvdhr%?\\t%V0, %R1\";
@@ -466,7 +466,7 @@ 
     case 0:
     case 1:
     case 2:
-      return (output_move_double (operands));
+      return (output_move_double (operands, 1, NULL));
 
     case 3: return \"cfmv64lr%?\\t%V0, %Q1\;cfmv64hr%?\\t%V0, %R1\";
     case 4: return \"cfmvr64l%?\\t%Q0, %V1\;cfmvr64h%?\\t%R0, %V1\";
@@ -522,7 +522,7 @@ 
     {
     case 0: return \"ldm%?ia\\t%m1, %M0\\t%@ double\";
     case 1: return \"stm%?ia\\t%m0, %M1\\t%@ double\";
-    case 2: case 3: case 4: return output_move_double (operands);
+    case 2: case 3: case 4: return output_move_double (operands, 1, NULL);
     case 5: return \"cfcpyd%?\\t%V0, %V1\";
     case 6: return \"cfldrd%?\\t%V0, %1\";
     case 7: return \"cfmvdlr\\t%V0, %Q1\;cfmvdhr%?\\t%V0, %R1\";
diff --git a/gcc/config/arm/fpa.md b/gcc/config/arm/fpa.md
index 6e6dd8d..3d41950 100644
--- a/gcc/config/arm/fpa.md
+++ b/gcc/config/arm/fpa.md
@@ -567,7 +567,7 @@ 
     case 0: return \"ldm%(ia%)\\t%m1, %M0\\t%@ double\";
     case 1: return \"stm%(ia%)\\t%m0, %M1\\t%@ double\";
     case 2: return \"#\";
-    case 3: case 4: return output_move_double (operands);
+    case 3: case 4: return output_move_double (operands, 1, NULL);
     case 5: return \"mvf%?d\\t%0, %1\";
     case 6: return \"mnf%?d\\t%0, #%N1\";
     case 7: return \"ldf%?d\\t%0, %1\";
@@ -657,7 +657,7 @@ 
     default:
     case 0: return \"ldm%(ia%)\\t%m1, %M0\\t%@ double\";
     case 1: return \"stm%(ia%)\\t%m0, %M1\\t%@ double\";
-    case 2: case 3: case 4: return output_move_double (operands);
+    case 2: case 3: case 4: return output_move_double (operands, 1, NULL);
     case 5: return \"mvf%?d\\t%0, %1\";
     case 6: return \"mnf%?d\\t%0, #%N1\";
     case 7: return \"ldf%?d\\t%0, %1\";
diff --git a/gcc/config/arm/iwmmxt.md b/gcc/config/arm/iwmmxt.md
index 7f13ae4..b066157 100644
--- a/gcc/config/arm/iwmmxt.md
+++ b/gcc/config/arm/iwmmxt.md
@@ -76,7 +76,7 @@ 
   switch (which_alternative)
     {
     default:
-      return output_move_double (operands);
+      return output_move_double (operands, 1, NULL);
     case 0:
       return \"#\";
     case 3:
@@ -173,7 +173,7 @@ 
    case 3: return \"tmrrc%?\\t%Q0, %R0, %1\";
    case 4: return \"tmcrr%?\\t%0, %Q1, %R1\";
    case 5: return \"#\";
-   default: return output_move_double (operands);
+   default: return output_move_double (operands, 1, NULL);
    }"
   [(set_attr "predicable" "yes")
    (set_attr "length"         "4,     4,   4,4,4,8,   8,8")
diff --git a/gcc/config/arm/neon.md b/gcc/config/arm/neon.md
index 1f9ea67..6d61233 100644
--- a/gcc/config/arm/neon.md
+++ b/gcc/config/arm/neon.md
@@ -190,7 +190,7 @@ 
     case 2: gcc_unreachable ();
     case 4: return "vmov\t%Q0, %R0, %P1  @ <mode>";
     case 5: return "vmov\t%P0, %Q1, %R1  @ <mode>";
-    default: return output_move_double (operands);
+    default: return output_move_double (operands, 1, NULL);
     }
 }
  [(set_attr "neon_type" "neon_int_1,*,neon_vmov,*,neon_mrrc,neon_mcr_2_mcrr,*,*,*")
diff --git a/gcc/config/arm/vfp.md b/gcc/config/arm/vfp.md
index 3311ae0..82f96f0 100644
--- a/gcc/config/arm/vfp.md
+++ b/gcc/config/arm/vfp.md
@@ -150,7 +150,7 @@ 
     case 4:
     case 5:
     case 6:
-      return output_move_double (operands);
+      return output_move_double (operands, 1, NULL);
     case 7:
       return \"fmdrr%?\\t%P0, %Q1, %R1\\t%@ int\";
     case 8:
@@ -199,7 +199,7 @@ 
     case 4:
     case 5:
     case 6:
-      return output_move_double (operands);
+      return output_move_double (operands, 1, NULL);
     case 7:
       return \"fmdrr%?\\t%P0, %Q1, %R1\\t%@ int\";
     case 8:
@@ -213,10 +213,19 @@ 
     }
   "
   [(set_attr "type" "*,*,*,*,load2,load2,store2,r_2_f,f_2_r,ffarithd,f_loadd,f_stored")
-   (set_attr "length" "4,8,12,16,8,8,8,4,4,4,4,4")
+   (set (attr "length") (cond [(eq_attr "alternative" "1") (const_int 8)
+                               (eq_attr "alternative" "2") (const_int 12)
+                               (eq_attr "alternative" "3") (const_int 16)
+                               (eq_attr "alternative" "4,5,6") 
+			       (symbol_ref 
+				"arm_count_output_move_double_insns (operands) \
+                                 * 4")]
+                              (const_int 4)))
    (set_attr "predicable"    "yes")
    (set_attr "pool_range"     "*,*,*,*,1020,4096,*,*,*,*,1020,*")
    (set_attr "neg_pool_range" "*,*,*,*,1008,0,*,*,*,*,1008,*")
+   (set (attr "ce_count") 
+	(symbol_ref "arm_count_output_move_double_insns (operands)"))
    (set_attr "arch"           "t2,any,any,any,a,t2,any,any,any,any,any,any")]
  )
 
@@ -427,7 +436,7 @@ 
       case 3: case 4:
 	return output_move_vfp (operands);
       case 5: case 6:
-	return output_move_double (operands);
+	return output_move_double (operands, 1, NULL);
       case 7:
 	if (TARGET_VFP_SINGLE)
 	  return \"fcpys%?\\t%0, %1\;fcpys%?\\t%p0, %p1\";
@@ -473,7 +482,7 @@ 
       case 3: case 4:
 	return output_move_vfp (operands);
       case 5: case 6: case 8:
-	return output_move_double (operands);
+	return output_move_double (operands, 1, NULL);
       case 7:
 	if (TARGET_VFP_SINGLE)
 	  return \"fcpys%?\\t%0, %1\;fcpys%?\\t%p0, %p1\";