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]

[PATCH, ARM] Fix generation of LDRD/STRD on Thumb-2


This patch fixes a bug in the Thumb-2 code generation where we would
incorrectly generate two 32-bit load instructions.  Because of the
different offset ranges, in addition to being less efficient, this
generated code that would not always assemble.

2009-01-13  Richard Earnshaw  <rearnsha@arm.com>

	* arm.c (output_move_double): Don't synthesize thumb-2 ldrd/strd with
	two 32-bit instructions.

*** arm.c	(revision 143352)
--- arm.c	(local)
*************** neon_valid_immediate (rtx op, enum machi
*** 6377,6383 ****
        break;					\
      }
  
!   unsigned int i, elsize, idx = 0, n_elts = CONST_VECTOR_NUNITS (op);
    unsigned int innersize = GET_MODE_SIZE (GET_MODE_INNER (mode));
    unsigned char bytes[16];
    int immtype = -1, matches;
--- 6377,6383 ----
        break;					\
      }
  
!   unsigned int i, elsize = 0, idx = 0, n_elts = CONST_VECTOR_NUNITS (op);
    unsigned int innersize = GET_MODE_SIZE (GET_MODE_INNER (mode));
    unsigned char bytes[16];
    int immtype = -1, matches;
*************** output_move_double (rtx *operands)
*** 10391,10426 ****
  		}
  	      else
  		{
! 		  /* IWMMXT allows offsets larger than ldrd can handle,
! 		     fix these up with a pair of ldr.  */
! 		  if (GET_CODE (otherops[2]) == CONST_INT
! 		      && (INTVAL(otherops[2]) <= -256
! 			  || INTVAL(otherops[2]) >= 256))
  		    {
  		      output_asm_insn ("ldr%?\t%0, [%1, %2]!", otherops);
! 		      otherops[0] = gen_rtx_REG (SImode, 1 + reg0);
! 		      output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
  		    }
- 		  else
- 		    output_asm_insn ("ldr%(d%)\t%0, [%1, %2]!", otherops);
  		}
  	    }
  	  else
  	    {
! 	      /* IWMMXT allows offsets larger than ldrd can handle,
  		 fix these up with a pair of ldr.  */
! 	      if (GET_CODE (otherops[2]) == CONST_INT
! 		  && (INTVAL(otherops[2]) <= -256
! 		      || INTVAL(otherops[2]) >= 256))
  		{
! 		  otherops[0] = gen_rtx_REG (SImode, 1 + reg0);
! 		  output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
! 		  otherops[0] = operands[0];
  		  output_asm_insn ("ldr%?\t%0, [%1], %2", otherops);
  		}
- 	      else
- 		/* We only allow constant increments, so this is safe.  */
- 		output_asm_insn ("ldr%(d%)\t%0, [%1], %2", otherops);
  	    }
  	  break;
  
--- 10391,10426 ----
  		}
  	      else
  		{
! 		  /* Use a single insn if we can.
! 		     FIXME: IWMMXT allows offsets larger than ldrd can
! 		     handle, fix these up with a pair of ldr.  */
! 		  if (TARGET_THUMB2
! 		      || GET_CODE (otherops[2]) != CONST_INT
! 		      || (INTVAL (otherops[2]) > -256
! 			  && INTVAL (otherops[2]) < 256))
! 		    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);
  		    }
  		}
  	    }
  	  else
  	    {
! 	      /* Use a single insn if we can.
! 		 FIXME: IWMMXT allows offsets larger than ldrd can handle,
  		 fix these up with a pair of ldr.  */
! 	      if (TARGET_THUMB2
! 		  || GET_CODE (otherops[2]) != CONST_INT
! 		  || (INTVAL (otherops[2]) > -256
! 		      && INTVAL (otherops[2]) < 256))
! 		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);
  		}
  	    }
  	  break;
  
*************** output_move_double (rtx *operands)
*** 10474,10479 ****
--- 10474,10480 ----
  		  operands[1] = otherops[0];
  		  if (TARGET_LDRD
  		      && (GET_CODE (otherops[2]) == REG
+ 			  || TARGET_THUMB2
  			  || (GET_CODE (otherops[2]) == CONST_INT
  			      && INTVAL (otherops[2]) > -256
  			      && INTVAL (otherops[2]) < 256)))
*************** output_move_double (rtx *operands)
*** 10586,10608 ****
  
  	  /* IWMMXT allows offsets larger than ldrd can handle,
  	     fix these up with a pair of ldr.  */
! 	  if (GET_CODE (otherops[2]) == CONST_INT
  	      && (INTVAL(otherops[2]) <= -256
  		  || INTVAL(otherops[2]) >= 256))
  	    {
- 	      rtx reg1;
- 	      reg1 = gen_rtx_REG (SImode, 1 + REGNO (operands[1]));
  	      if (GET_CODE (XEXP (operands[0], 0)) == PRE_MODIFY)
  		{
  		  output_asm_insn ("ldr%?\t%0, [%1, %2]!", otherops);
! 		  otherops[0] = reg1;
! 		  output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
  		}
  	      else
  		{
! 		  otherops[0] = reg1;
! 		  output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
! 		  otherops[0] = operands[1];
  		  output_asm_insn ("ldr%?\t%0, [%1], %2", otherops);
  		}
  	    }
--- 10587,10605 ----
  
  	  /* IWMMXT allows offsets larger than ldrd can handle,
  	     fix these up with a pair of ldr.  */
! 	  if (!TARGET_THUMB2
! 	      && GET_CODE (otherops[2]) == CONST_INT
  	      && (INTVAL(otherops[2]) <= -256
  		  || INTVAL(otherops[2]) >= 256))
  	    {
  	      if (GET_CODE (XEXP (operands[0], 0)) == PRE_MODIFY)
  		{
  		  output_asm_insn ("ldr%?\t%0, [%1, %2]!", otherops);
! 		  output_asm_insn ("ldr%?\t%H0, [%1, #4]", otherops);
  		}
  	      else
  		{
! 		  output_asm_insn ("ldr%?\t%H0, [%1, #4]", otherops);
  		  output_asm_insn ("ldr%?\t%0, [%1], %2", otherops);
  		}
  	    }
*************** output_move_double (rtx *operands)
*** 10637,10642 ****
--- 10634,10640 ----
  	    }
  	  if (TARGET_LDRD
  	      && (GET_CODE (otherops[2]) == REG
+ 		  || TARGET_THUMB2
  		  || (GET_CODE (otherops[2]) == CONST_INT
  		      && INTVAL (otherops[2]) > -256
  		      && INTVAL (otherops[2]) < 256)))
*************** output_move_double (rtx *operands)
*** 10650,10658 ****
  
          default:
  	  otherops[0] = adjust_address (operands[0], SImode, 4);
! 	  otherops[1] = gen_rtx_REG (SImode, 1 + REGNO (operands[1]));
  	  output_asm_insn ("str%?\t%1, %0", operands);
! 	  output_asm_insn ("str%?\t%1, %0", otherops);
  	}
      }
  
--- 10648,10656 ----
  
          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);
  	}
      }
  

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