[csl-arm-branch] Add sign/zero extend instructions.

Richard Earnshaw rearnsha@arm.com
Wed Jan 7 14:08:00 GMT 2004


> The attached patch adds patterns for the armv6 sign/zero extend instructions, 
> including the extend and add insns.
> It currently only implements the unrotated variants.
> 
> Tested with cross-compiler to arm-none-elf/mcpu=arm1136js.
> 
> Ok?
> 
> Paul
> 
> 2003-12-23  Paul Brook  <paul@codesourcery.com>
> 
> 	* config/arm/arm.c (arm_arch6j): New variable.
> 	(arm_override_options): Set it.
> 	(arm_emit_extendsi): New function.
> 	* config/arm/arm-protos.h (arm_emit_extendsi): Add prototype.
> 	* config/arm/arm.h (arm_arch6j): Declare.
> 	* config/arm/arm.md: Add sign/zero extend insns.
> 

Paul,

I don't think the arm_emit_extendsi function is safe -- you shouldn't be 
modifying part of an operand passed into an expander, since you don't know 
what else might be using it.  Secondly, I don't think you should be 
restricting this to

  (subreg:HI (reg:SI) 0)

It should be perfectly ok to match

  (reg:HI)

as well (this gives the optimizer more freedom).

Further, the load-extend and simple register-extend operations should 
share a common pattern -- then if reloading is needed the compiler can 
simply do the right thing -- without that we might end up with sequences 
like

	ldrh	r0, [stack slot]
	uxth	r0, r0

The second instruction is redundant.

Finally, you'd missed the attributes off the new patterns, so the compiler 
didn't know the size or the scheduling requirements.

Just for the moment I've classified these instructions as alu_shift (the 
arm11 manual suggests they have an early reg as a shift operand would do, 
but I need to enquire further whether that is really the case).

I've fixed all the above problems and checked in the new code.

R.

2004-01-07  Richard Earnshaw  <rearnsha@arm.com>

	* arm.c (arm_emit_extendsi): Delete.
	* arm-protos.h (arm_emit_extendsi): Delete.
	* arm.md (zero_extendhisi2): Also handle zero-extension of 
	non-subregs.
	(zero_extendqisi2, extendhisi2, extendqisi2): Likewise.
	(thumb_zero_extendhisi2): Only match if not v6.
	(arm_zero_extendhisi2, thumb_zero_extendqisi2, arm_zero_extendqisi2)
	(thumb_extendhisi2, arm_extendhisi2, arm_extendqisi)
	(thumb_extendqisi2): Likewise.
	(thumb_zero_extendhisi2_v6, arm_zero_extendhisi2_v6): New patterns.
	(thumb_zero_extendqisi2_v6, arm_zero_extendqisi2_v6): New patterns.
	(thumb_extendhisi2_insn_v6, arm_extendhisi2_v6): New patterns.
	(thumb_extendqisi2_v6, arm_extendqisi_v6): New patterns.
	(arm_zero_extendhisi2_reg, arm_zero_extendqisi2_reg): Delete.
	(arm_extendhisi2_reg, arm_extendqisi2_reg): Delete.
	(arm_zero_extendhisi2addsi): Remove subreg.  Add attributes.
	(arm_zero_extendqisi2addsi, arm_extendhisi2addsi): Likewise.
	(arm_extendqisi2addsi): Likewise.


-------------- next part --------------
Index: arm-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm-protos.h,v
retrieving revision 1.60.4.4
diff -p -w -r1.60.4.4 arm-protos.h
*** arm-protos.h	24 Dec 2003 11:51:58 -0000	1.60.4.4
--- arm-protos.h	7 Jan 2004 12:32:20 -0000
*************** extern void arm_final_prescan_insn (rtx)
*** 140,146 ****
  extern int arm_go_if_legitimate_address (enum machine_mode, rtx);
  extern int arm_debugger_arg_offset (int, rtx);
  extern int arm_is_longcall_p (rtx, int, int);
- extern int arm_emit_extendsi (enum rtx_code, rtx, rtx);
  extern int    arm_emit_vector_const (FILE *, rtx);
  extern const char * arm_output_load_gr (rtx *);
  
--- 140,145 ----
Index: arm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.c,v
retrieving revision 1.303.2.11
diff -p -w -r1.303.2.11 arm.c
*** arm.c	31 Dec 2003 00:44:18 -0000	1.303.2.11
--- arm.c	7 Jan 2004 12:32:20 -0000
*************** arm_output_mi_thunk (FILE *file, tree th
*** 13482,13521 ****
      }
  }
  
- /* Emit RTL for a sign/zero extend insn.  */
- int
- arm_emit_extendsi (enum rtx_code code, rtx op0, rtx op1)
- {
-   rtx tmp;
-   rtx *p;
- 
-   if (GET_CODE (op1) != SUBREG
-       || !arm_arch6j)
-     return 0;
- 
-   p = &XEXP (op1, 0);
-   if (GET_CODE (*p) != REG)
-     return 0;
- 
-   if (XINT (op1, 1) != 0)
-     return 0;
- 
-   /* Put the low part of multiword regs into an SImode reg so we only
-      have to deal with subregs of SImode regs.  */
-   if (GET_MODE (*p) != SImode)
-     {
-       tmp = gen_reg_rtx (SImode);
-       emit_insn (gen_rtx_SET (VOIDmode, tmp,
- 		 gen_lowpart (SImode, *p)));
-       *p = tmp;
-     }
- 
-   emit_insn (gen_rtx_SET (VOIDmode, op0,
- 	     gen_rtx_fmt_e (code, SImode, op1)));
-   return 1;
- }
- 
- 
  int
  arm_emit_vector_const (FILE *file, rtx x)
  {
--- 13482,13487 ----
Index: arm.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.md,v
retrieving revision 1.145.2.10
diff -p -w -r1.145.2.10 arm.md
*** arm.md	31 Dec 2003 00:44:19 -0000	1.145.2.10
--- arm.md	7 Jan 2004 12:32:20 -0000
***************
*** 3145,3193 ****
  	  rather than an LDR instruction, so we cannot get an unaligned
  	  word access.  */
  	emit_insn (gen_rtx_SET (VOIDmode, operands[0],
! 				gen_rtx_ZERO_EXTEND (SImode,
! 						     operands[1])));
  	DONE;
        }
      if (TARGET_ARM && TARGET_MMU_TRAPS && GET_CODE (operands[1]) == MEM)
        {
  	emit_insn (gen_movhi_bytes (operands[0], operands[1]));
  	DONE;
        }
!     if (arm_emit_extendsi (ZERO_EXTEND, operands[0], operands[1]))
!       DONE;
      if (!s_register_operand (operands[1], HImode))
        operands[1] = copy_to_mode_reg (HImode, operands[1]);
-     operands[1] = gen_lowpart (SImode, operands[1]);
-     operands[2] = gen_reg_rtx (SImode);
  	    
!     if (TARGET_THUMB)
        {
! 	rtx ops[3];
! 	
! 	ops[0] = operands[2];
! 	ops[1] = operands[1];
! 	ops[2] = GEN_INT (16);
! 	
! 	emit_insn (gen_rtx_SET (VOIDmode, ops[0],
! 				gen_rtx_ASHIFT (SImode, ops[1], ops[2])));
! 
! 	ops[0] = operands[0];
! 	ops[1] = operands[2];
! 	ops[2] = GEN_INT (16);
! 
! 	emit_insn (gen_rtx_SET (VOIDmode, ops[0],
! 				gen_rtx_LSHIFTRT (SImode, ops[1],
! 						  ops[2])));
  	DONE; 
        }
    }"
  )
  
  (define_insn "*thumb_zero_extendhisi2"
    [(set (match_operand:SI                 0 "register_operand" "=l")
  	(zero_extend:SI (match_operand:HI 1 "memory_operand"    "m")))]
!   "TARGET_THUMB"
    "*
    rtx mem = XEXP (operands[1], 0);
  
--- 3145,3179 ----
  	  rather than an LDR instruction, so we cannot get an unaligned
  	  word access.  */
  	emit_insn (gen_rtx_SET (VOIDmode, operands[0],
! 				gen_rtx_ZERO_EXTEND (SImode, operands[1])));
  	DONE;
        }
+ 
      if (TARGET_ARM && TARGET_MMU_TRAPS && GET_CODE (operands[1]) == MEM)
        {
  	emit_insn (gen_movhi_bytes (operands[0], operands[1]));
  	DONE;
        }
! 
      if (!s_register_operand (operands[1], HImode))
        operands[1] = copy_to_mode_reg (HImode, operands[1]);
  
!     if (arm_arch6j)
        {
! 	emit_insn (gen_rtx_SET (VOIDmode, operands[0],
! 				gen_rtx_ZERO_EXTEND (SImode, operands[1])));
  	DONE;
        }
+ 
+     operands[1] = gen_lowpart (SImode, operands[1]);
+     operands[2] = gen_reg_rtx (SImode);
    }"
  )
  
  (define_insn "*thumb_zero_extendhisi2"
    [(set (match_operand:SI 0 "register_operand" "=l")
  	(zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
!   "TARGET_THUMB && !arm_arch6j"
    "*
    rtx mem = XEXP (operands[1], 0);
  
***************
*** 3226,3235 ****
     (set_attr "pool_range" "60")]
  )
  
  (define_insn "*arm_zero_extendhisi2"
    [(set (match_operand:SI                 0 "s_register_operand" "=r")
  	(zero_extend:SI (match_operand:HI 1 "memory_operand"      "m")))]
!   "TARGET_ARM && arm_arch4"
    "ldr%?h\\t%0, %1"
    [(set_attr "type" "load_byte")
     (set_attr "predicable" "yes")
--- 3212,3268 ----
     (set_attr "pool_range" "60")]
  )
  
+ (define_insn "*thumb_zero_extendhisi2_v6"
+   [(set (match_operand:SI 0 "register_operand" "=l,l")
+ 	(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "l,m")))]
+   "TARGET_THUMB && arm_arch6j"
+   "*
+   rtx mem;
+ 
+   if (which_alternative == 0)
+     return \"uxth\\t%0, %1\";
+ 
+   mem = XEXP (operands[1], 0);
+ 
+   if (GET_CODE (mem) == CONST)
+     mem = XEXP (mem, 0);
+     
+   if (GET_CODE (mem) == LABEL_REF)
+     return \"ldr\\t%0, %1\";
+     
+   if (GET_CODE (mem) == PLUS)
+     {
+       rtx a = XEXP (mem, 0);
+       rtx b = XEXP (mem, 1);
+ 
+       /* This can happen due to bugs in reload.  */
+       if (GET_CODE (a) == REG && REGNO (a) == SP_REGNUM)
+         {
+           rtx ops[2];
+           ops[0] = operands[0];
+           ops[1] = a;
+       
+           output_asm_insn (\"mov	%0, %1\", ops);
+ 
+           XEXP (mem, 0) = operands[0];
+        }
+ 
+       else if (   GET_CODE (a) == LABEL_REF
+ 	       && GET_CODE (b) == CONST_INT)
+         return \"ldr\\t%0, %1\";
+     }
+     
+   return \"ldrh\\t%0, %1\";
+   "
+   [(set_attr "length" "2,4")
+    (set_attr "type" "alu_shift,load_byte")
+    (set_attr "pool_range" "*,60")]
+ )
+ 
  (define_insn "*arm_zero_extendhisi2"
    [(set (match_operand:SI 0 "s_register_operand" "=r")
  	(zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
!   "TARGET_ARM && arm_arch4 && !arm_arch6j"
    "ldr%?h\\t%0, %1"
    [(set_attr "type" "load_byte")
     (set_attr "predicable" "yes")
***************
*** 3237,3257 ****
     (set_attr "neg_pool_range" "244")]
  )
  
! (define_insn "*arm_zero_extendhisi2_reg"
!   [(set (match_operand:SI		  0 "s_register_operand" "=r")
! 	(zero_extend:SI (subreg:HI
! 	    (match_operand:SI 1 "s_register_operand" "r") 0)))]
!   "TARGET_EITHER && arm_arch6j"
!   "uxth%?\\t%0, %1"
  )
  
  (define_insn "*arm_zero_extendhisi2addsi"
    [(set (match_operand:SI	    0 "s_register_operand" "=r")
! 	(plus:SI (zero_extend:SI (subreg:HI
! 		  (match_operand:SI 1 "s_register_operand" "r") 0))
  		(match_operand:SI   2 "s_register_operand" "r")))]
    "TARGET_ARM && arm_arch6j"
    "uxtah%?\\t%0, %2, %1"
  )
  
  (define_split
--- 3270,3296 ----
     (set_attr "neg_pool_range" "244")]
  )
  
! (define_insn "*arm_zero_extendhisi2_v6"
!   [(set (match_operand:SI 0 "s_register_operand" "=r,r")
! 	(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
!   "TARGET_ARM && arm_arch6j"
!   "@
!    uxth%?\\t%0, %1
!    ldr%?h\\t%0, %1"
!   [(set_attr "type" "alu_shift,load_byte")
!    (set_attr "predicable" "yes")
!    (set_attr "pool_range" "*,256")
!    (set_attr "neg_pool_range" "*,244")]
  )
  
  (define_insn "*arm_zero_extendhisi2addsi"
    [(set (match_operand:SI 0 "s_register_operand" "=r")
! 	(plus:SI (zero_extend:SI (match_operand:HI 1 "s_register_operand" "r"))
  		 (match_operand:SI 2 "s_register_operand" "r")))]
    "TARGET_ARM && arm_arch6j"
    "uxtah%?\\t%0, %2, %1"
+   [(set_attr "type" "alu_shift")
+    (set_attr "predicable" "yes")]
  )
  
  (define_split
***************
*** 3289,3297 ****
  	(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
    "TARGET_EITHER"
    "
!   if (arm_emit_extendsi (ZERO_EXTEND, operands[0], operands[1]))
!     DONE;
!   if (GET_CODE (operands[1]) != MEM)
      {
        if (TARGET_ARM)
          {
--- 3328,3334 ----
  	(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
    "TARGET_EITHER"
    "
!   if (!arm_arch6j && GET_CODE (operands[1]) != MEM)
      {
        if (TARGET_ARM)
          {
***************
*** 3329,3345 ****
  (define_insn "*thumb_zero_extendqisi2"
    [(set (match_operand:SI                 0 "register_operand" "=l")
  	(zero_extend:SI (match_operand:QI 1 "memory_operand"    "m")))]
!   "TARGET_THUMB"
    "ldrb\\t%0, %1"
    [(set_attr "length" "2")
     (set_attr "type" "load_byte")
     (set_attr "pool_range" "32")]
  )
  
  (define_insn "*arm_zero_extendqisi2"
    [(set (match_operand:SI                 0 "s_register_operand" "=r")
  	(zero_extend:SI (match_operand:QI 1 "memory_operand"      "m")))]
!   "TARGET_ARM"
    "ldr%?b\\t%0, %1\\t%@ zero_extendqisi2"
    [(set_attr "type" "load_byte")
     (set_attr "predicable" "yes")
--- 3366,3394 ----
  (define_insn "*thumb_zero_extendqisi2"
    [(set (match_operand:SI 0 "register_operand" "=l")
  	(zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
!   "TARGET_THUMB && !arm_arch6j"
    "ldrb\\t%0, %1"
    [(set_attr "length" "2")
     (set_attr "type" "load_byte")
     (set_attr "pool_range" "32")]
  )
  
+ (define_insn "*thumb_zero_extendqisi2_v6"
+   [(set (match_operand:SI 0 "register_operand" "=l,l")
+ 	(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "l,m")))]
+   "TARGET_THUMB && arm_arch6j"
+   "@
+    uxtb\\t%0, %1
+    ldrb\\t%0, %1"
+   [(set_attr "length" "2,2")
+    (set_attr "type" "alu_shift,load_byte")
+    (set_attr "pool_range" "*,32")]
+ )
+ 
  (define_insn "*arm_zero_extendqisi2"
    [(set (match_operand:SI 0 "s_register_operand" "=r")
  	(zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
!   "TARGET_ARM && !arm_arch6j"
    "ldr%?b\\t%0, %1\\t%@ zero_extendqisi2"
    [(set_attr "type" "load_byte")
     (set_attr "predicable" "yes")
***************
*** 3347,3367 ****
     (set_attr "neg_pool_range" "4084")]
  )
  
! (define_insn "*arm_zero_extendqisi2_reg"
!   [(set (match_operand:SI		  0 "s_register_operand" "=r")
! 	(zero_extend:SI (subreg:QI
! 	    (match_operand:SI 1 "s_register_operand" "r") 0)))]
!   "TARGET_EITHER && arm_arch6j"
!   "uxtb%?\\t%0, %1"
  )
  
  (define_insn "*arm_zero_extendqisi2addsi"
    [(set (match_operand:SI	    0 "s_register_operand" "=r")
! 	(plus:SI (zero_extend:SI (subreg:QI
! 		  (match_operand:SI 1 "s_register_operand" "r") 0))
  		(match_operand:SI   2 "s_register_operand" "r")))]
    "TARGET_ARM && arm_arch6j"
    "uxtab%?\\t%0, %2, %1"
  )
  
  (define_split
--- 3396,3422 ----
     (set_attr "neg_pool_range" "4084")]
  )
  
! (define_insn "*arm_zero_extendqisi2_v6"
!   [(set (match_operand:SI 0 "s_register_operand" "=r,r")
! 	(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
!   "TARGET_ARM && arm_arch6j"
!   "@
!    uxtb%?\\t%0, %1
!    ldr%?b\\t%0, %1\\t%@ zero_extendqisi2"
!   [(set_attr "type" "alu_shift,load_byte")
!    (set_attr "predicable" "yes")
!    (set_attr "pool_range" "*,4096")
!    (set_attr "neg_pool_range" "*,4084")]
  )
  
  (define_insn "*arm_zero_extendqisi2addsi"
    [(set (match_operand:SI 0 "s_register_operand" "=r")
! 	(plus:SI (zero_extend:SI (match_operand:QI 1 "s_register_operand" "r"))
  		 (match_operand:SI 2 "s_register_operand" "r")))]
    "TARGET_ARM && arm_arch6j"
    "uxtab%?\\t%0, %2, %1"
+   [(set_attr "predicable" "yes")
+    (set_attr "type" "alu_shift")]
  )
  
  (define_split
***************
*** 3393,3399 ****
    "TARGET_EITHER"
    "
    {
!     if (TARGET_ARM && arm_arch4 && GET_CODE (operands[1]) == MEM)
        {
         /* Note: We do not have to worry about TARGET_MMU_TRAPS
  	  here because the insn below will generate an LDRH instruction
--- 3448,3461 ----
    "TARGET_EITHER"
    "
    {
!     if (GET_CODE (operands[1]) == MEM)
!       {
! 	if (TARGET_THUMB)
! 	  {
! 	    emit_insn (gen_thumb_extendhisi2 (operands[0], operands[1]));
! 	    DONE;
!           }
! 	else if (arm_arch4)
  	  {
  	    /* Note: We do not have to worry about TARGET_MMU_TRAPS
  	       here because the insn below will generate an LDRH instruction
***************
*** 3403,3449 ****
  		   gen_rtx_SIGN_EXTEND (SImode, operands[1])));
          DONE;
        }
  
      if (TARGET_ARM && TARGET_MMU_TRAPS && GET_CODE (operands[1]) == MEM)
        {
          emit_insn (gen_extendhisi2_mem (operands[0], operands[1]));
          DONE;
        }
!       if (arm_emit_extendsi (SIGN_EXTEND, operands[0], operands[1]))
! 	DONE;
      if (!s_register_operand (operands[1], HImode))
        operands[1] = copy_to_mode_reg (HImode, operands[1]);
-     operands[1] = gen_lowpart (SImode, operands[1]);
-     operands[2] = gen_reg_rtx (SImode);
  
!     if (TARGET_THUMB)
        {
! 	rtx ops[3];
! 	
! 	ops[0] = operands[2];
! 	ops[1] = operands[1];
! 	ops[2] = GEN_INT (16);
! 	
!         emit_insn (gen_rtx_SET (VOIDmode, ops[0],
! 				gen_rtx_ASHIFT (SImode, ops[1], ops[2])));
! 	    
! 	ops[0] = operands[0];
! 	ops[1] = operands[2];
! 	ops[2] = GEN_INT (16);
! 	
!         emit_insn (gen_rtx_SET (VOIDmode, ops[0],
! 				gen_rtx_ASHIFTRT (SImode, ops[1], ops[2])));
  	
  	DONE;
        }
    }"
  )
  
! (define_insn "*thumb_extendhisi2_insn"
    [(set (match_operand:SI                 0 "register_operand" "=l")
  	(sign_extend:SI (match_operand:HI 1 "memory_operand"    "m")))
     (clobber (match_scratch:SI             2                   "=&l"))]
!   "TARGET_THUMB"
    "*
    {
      rtx ops[4];
--- 3465,3502 ----
  		       gen_rtx_SIGN_EXTEND (SImode, operands[1])));
  	    DONE;
  	  }
+       }
  
      if (TARGET_ARM && TARGET_MMU_TRAPS && GET_CODE (operands[1]) == MEM)
        {
          emit_insn (gen_extendhisi2_mem (operands[0], operands[1]));
          DONE;
        }
! 
      if (!s_register_operand (operands[1], HImode))
        operands[1] = copy_to_mode_reg (HImode, operands[1]);
  
!     if (arm_arch6j)
        {
! 	if (TARGET_THUMB)
! 	  emit_insn (gen_thumb_extendhisi2 (operands[0], operands[1]));
! 	else
! 	  emit_insn (gen_rtx_SET (VOIDmode, operands[0],
! 		     gen_rtx_SIGN_EXTEND (SImode, operands[1])));
  
  	DONE;
        }
+ 
+     operands[1] = gen_lowpart (SImode, operands[1]);
+     operands[2] = gen_reg_rtx (SImode);
    }"
  )
  
! (define_insn "thumb_extendhisi2"
    [(set (match_operand:SI 0 "register_operand" "=l")
  	(sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))
     (clobber (match_scratch:SI 2 "=&l"))]
!   "TARGET_THUMB && !arm_arch6j"
    "*
    {
      rtx ops[4];
***************
*** 3497,3502 ****
--- 3550,3628 ----
     (set_attr "pool_range" "1020")]
  )
  
+ ;; We used to have an early-clobber on the scratch register here.
+ ;; However, there's a bug somewhere in reload which means that this
+ ;; can be partially ignored during spill allocation if the memory
+ ;; address also needs reloading; this causes an abort later on when
+ ;; we try to verify the operands.  Fortunately, we don't really need
+ ;; the early-clobber: we can always use operand 0 if operand 2
+ ;; overlaps the address.
+ (define_insn "*thumb_extendhisi2_insn_v6"
+   [(set (match_operand:SI 0 "register_operand" "=l,l")
+ 	(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "l,m")))
+    (clobber (match_scratch:SI 2 "=X,l"))]
+   "TARGET_THUMB && arm_arch6j"
+   "*
+   {
+     rtx ops[4];
+     rtx mem;
+ 
+     if (which_alternative == 0)
+       return \"sxth\\t%0, %1\";
+ 
+     mem = XEXP (operands[1], 0);
+ 
+     /* This code used to try to use 'V', and fix the address only if it was
+        offsettable, but this fails for e.g. REG+48 because 48 is outside the
+        range of QImode offsets, and offsettable_address_p does a QImode
+        address check.  */
+        
+     if (GET_CODE (mem) == CONST)
+       mem = XEXP (mem, 0);
+     
+     if (GET_CODE (mem) == LABEL_REF)
+       return \"ldr\\t%0, %1\";
+     
+     if (GET_CODE (mem) == PLUS)
+       {
+         rtx a = XEXP (mem, 0);
+         rtx b = XEXP (mem, 1);
+ 
+         if (GET_CODE (a) == LABEL_REF
+ 	    && GET_CODE (b) == CONST_INT)
+           return \"ldr\\t%0, %1\";
+ 
+         if (GET_CODE (b) == REG)
+           return \"ldrsh\\t%0, %1\";
+ 	  
+         ops[1] = a;
+         ops[2] = b;
+       }
+     else
+       {
+         ops[1] = mem;
+         ops[2] = const0_rtx;
+       }
+       
+     if (GET_CODE (ops[1]) != REG)
+       {
+         debug_rtx (ops[1]);
+         abort ();
+       }
+ 
+     ops[0] = operands[0];
+     if (reg_mentioned_p (operands[2], ops[1]))
+       ops[3] = ops[0];
+     else
+       ops[3] = operands[2];
+     output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops);
+     return \"\";
+   }"
+   [(set_attr "length" "2,4")
+    (set_attr "type" "alu_shift,load_byte")
+    (set_attr "pool_range" "*,1020")]
+ )
+ 
  (define_expand "extendhisi2_mem"
    [(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" "")))
     (set (match_dup 3)
***************
*** 3534,3543 ****
    }"
  )
  
! (define_insn "*arm_extendhisi_insn"
    [(set (match_operand:SI                 0 "s_register_operand" "=r")
  	(sign_extend:SI (match_operand:HI 1 "memory_operand"      "m")))]
!   "TARGET_ARM && arm_arch4"
    "ldr%?sh\\t%0, %1"
    [(set_attr "type" "load_byte")
     (set_attr "predicable" "yes")
--- 3660,3669 ----
    }"
  )
  
! (define_insn "*arm_extendhisi2"
    [(set (match_operand:SI 0 "s_register_operand" "=r")
  	(sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
!   "TARGET_ARM && arm_arch4 && !arm_arch6j"
    "ldr%?sh\\t%0, %1"
    [(set_attr "type" "load_byte")
     (set_attr "predicable" "yes")
***************
*** 3545,3562 ****
     (set_attr "neg_pool_range" "244")]
  )
  
! (define_insn "*arm_extendhisi2_reg"
!   [(set (match_operand:SI		  0 "s_register_operand" "=r")
! 	(sign_extend:SI (subreg:HI
! 	    (match_operand:SI 1 "s_register_operand" "r") 0)))]
!   "TARGET_EITHER && arm_arch6j"
!   "sxth%?\\t%0, %1"
  )
  
  (define_insn "*arm_extendhisi2addsi"
    [(set (match_operand:SI	    0 "s_register_operand" "=r")
! 	(plus:SI (sign_extend:SI (subreg:HI
! 		  (match_operand:SI 1 "s_register_operand" "r") 0))
  		(match_operand:SI   2 "s_register_operand" "r")))]
    "TARGET_ARM && arm_arch6j"
    "sxtah%?\\t%0, %2, %1"
--- 3671,3692 ----
     (set_attr "neg_pool_range" "244")]
  )
  
! (define_insn "*arm_extendhisi2_v6"
!   [(set (match_operand:SI 0 "s_register_operand" "=r,r")
! 	(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
!   "TARGET_ARM && arm_arch6j"
!   "@
!    sxth%?\\t%0, %1
!    ldr%?sh\\t%0, %1"
!   [(set_attr "type" "alu_shift,load_byte")
!    (set_attr "predicable" "yes")
!    (set_attr "pool_range" "*,256")
!    (set_attr "neg_pool_range" "*,244")]
  )
  
  (define_insn "*arm_extendhisi2addsi"
    [(set (match_operand:SI 0 "s_register_operand" "=r")
! 	(plus:SI (sign_extend:SI (match_operand:HI 1 "s_register_operand" "r"))
  		 (match_operand:SI 2 "s_register_operand" "r")))]
    "TARGET_ARM && arm_arch6j"
    "sxtah%?\\t%0, %2, %1"
***************
*** 3679,3727 ****
    "TARGET_EITHER"
    "
    {
!     if (TARGET_ARM && arm_arch4 && GET_CODE (operands[1]) == MEM)
        {
!         emit_insn (gen_rtx_SET (VOIDmode,
! 			        operands[0],
  			        gen_rtx_SIGN_EXTEND (SImode, operands[1])));
          DONE;
        }
!     if (arm_emit_extendsi (SIGN_EXTEND, operands[0], operands[1]))
!       DONE;
      if (!s_register_operand (operands[1], QImode))
        operands[1] = copy_to_mode_reg (QImode, operands[1]);
-     operands[1] = gen_lowpart (SImode, operands[1]);
-     operands[2] = gen_reg_rtx (SImode);
      
!     if (TARGET_THUMB)
        {
! 	rtx ops[3];
! 	
! 	ops[0] = operands[2];
! 	ops[1] = operands[1];
! 	ops[2] = GEN_INT (24);
! 	
!         emit_insn (gen_rtx_SET (VOIDmode, ops[0],
! 		   gen_rtx_ASHIFT (SImode, ops[1], ops[2])));
! 
! 	ops[0] = operands[0];
! 	ops[1] = operands[2];
! 	ops[2] = GEN_INT (24);
! 	
!         emit_insn (gen_rtx_SET (VOIDmode, ops[0],
! 		   gen_rtx_ASHIFTRT (SImode, ops[1], ops[2])));
! 	
  	DONE;
        }
    }"
  )
  
  ; Rather than restricting all byte accesses to memory addresses that ldrsb
  ; can handle, we fix up the ones that ldrsb can't grok with a split.
! (define_insn "*arm_extendqisi_insn"
    [(set (match_operand:SI                 0 "s_register_operand" "=r")
  	(sign_extend:SI (match_operand:QI 1 "memory_operand"      "m")))]
!   "TARGET_ARM && arm_arch4"
    "*
    /* If the address is invalid, this will split the instruction into two.  */
    if (bad_signed_byte_operand (operands[1], VOIDmode))
--- 3809,3842 ----
    "TARGET_EITHER"
    "
    {
!     if ((TARGET_THUMB || arm_arch4) && GET_CODE (operands[1]) == MEM)
        {
!         emit_insn (gen_rtx_SET (VOIDmode, operands[0],
  			        gen_rtx_SIGN_EXTEND (SImode, operands[1])));
          DONE;
        }
! 
      if (!s_register_operand (operands[1], QImode))
        operands[1] = copy_to_mode_reg (QImode, operands[1]);
  
!     if (arm_arch6j)
        {
!         emit_insn (gen_rtx_SET (VOIDmode, operands[0],
! 			        gen_rtx_SIGN_EXTEND (SImode, operands[1])));
          DONE;
        }
+ 
+     operands[1] = gen_lowpart (SImode, operands[1]);
+     operands[2] = gen_reg_rtx (SImode);
    }"
  )
  
  ; Rather than restricting all byte accesses to memory addresses that ldrsb
  ; can handle, we fix up the ones that ldrsb can't grok with a split.
! (define_insn "*arm_extendqisi"
    [(set (match_operand:SI 0 "s_register_operand" "=r")
  	(sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
!   "TARGET_ARM && arm_arch4 && !arm_arch6j"
    "*
    /* If the address is invalid, this will split the instruction into two.  */
    if (bad_signed_byte_operand (operands[1], VOIDmode))
***************
*** 3735,3755 ****
     (set_attr "neg_pool_range" "244")]
  )
  
! (define_insn "*arm_extendqisi2_reg"
!   [(set (match_operand:SI		  0 "s_register_operand" "=r")
! 	(sign_extend:SI (subreg:QI
! 	    (match_operand:SI 1 "s_register_operand" "r") 0)))]
!   "TARGET_EITHER && arm_arch6j"
!   "sxtb%?\\t%0, %1"
  )
  
  (define_insn "*arm_extendqisi2addsi"
    [(set (match_operand:SI	    0 "s_register_operand" "=r")
! 	(plus:SI (sign_extend:SI (subreg:QI
! 		  (match_operand:SI 1 "s_register_operand" "r") 0))
  		(match_operand:SI   2 "s_register_operand" "r")))]
    "TARGET_ARM && arm_arch6j"
    "sxtab%?\\t%0, %2, %1"
  )
  
  (define_split
--- 3850,3884 ----
     (set_attr "neg_pool_range" "244")]
  )
  
! (define_insn "*arm_extendqisi_v6"
!   [(set (match_operand:SI 0 "s_register_operand" "=r,r")
! 	(sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
!   "TARGET_ARM && arm_arch6j"
!   "*
!   if (which_alternative == 0)
!     return \"sxtb%?\\t%0, %1\";
! 
!   /* If the address is invalid, this will split the instruction into two.  */
!   if (bad_signed_byte_operand (operands[1], VOIDmode))
!     return \"#\";
! 
!   return \"ldr%?sb\\t%0, %1\";
!   "
!   [(set_attr "type" "alu_shift,load_byte")
!    (set_attr "predicable" "yes")
!    (set_attr "length" "4,8")
!    (set_attr "pool_range" "*,256")
!    (set_attr "neg_pool_range" "*,244")]
  )
  
  (define_insn "*arm_extendqisi2addsi"
    [(set (match_operand:SI 0 "s_register_operand" "=r")
! 	(plus:SI (sign_extend:SI (match_operand:QI 1 "s_register_operand" "r"))
  		 (match_operand:SI 2 "s_register_operand" "r")))]
    "TARGET_ARM && arm_arch6j"
    "sxtab%?\\t%0, %2, %1"
+   [(set_attr "type" "alu_shift")
+    (set_attr "predicable" "yes")]
  )
  
  (define_split
***************
*** 3785,3794 ****
    }"
  )
  
! (define_insn "*thumb_extendqisi2_insn"
    [(set (match_operand:SI                 0 "register_operand" "=l,l")
  	(sign_extend:SI (match_operand:QI 1 "memory_operand"    "V,m")))]
!   "TARGET_THUMB"
    "*
    {
      rtx ops[3];
--- 3914,3923 ----
    }"
  )
  
! (define_insn "*thumb_extendqisi2"
    [(set (match_operand:SI 0 "register_operand" "=l,l")
  	(sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))]
!   "TARGET_THUMB && !arm_arch6j"
    "*
    {
      rtx ops[3];
***************
*** 3862,3867 ****
--- 3991,4077 ----
    [(set_attr "length" "2,6")
     (set_attr "type" "load_byte,load_byte")
     (set_attr "pool_range" "32,32")]
+ )
+ 
+ (define_insn "*thumb_extendqisi2_v6"
+   [(set (match_operand:SI 0 "register_operand" "=l,l,l")
+ 	(sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "l,V,m")))]
+   "TARGET_THUMB && arm_arch6j"
+   "*
+   {
+     rtx ops[3];
+     rtx mem;
+ 
+     if (which_alternative == 0)
+       return \"sxtb\\t%0, %1\";
+ 
+     mem = XEXP (operands[1], 0);
+     
+     if (GET_CODE (mem) == CONST)
+       mem = XEXP (mem, 0);
+     
+     if (GET_CODE (mem) == LABEL_REF)
+       return \"ldr\\t%0, %1\";
+ 
+     if (GET_CODE (mem) == PLUS
+         && GET_CODE (XEXP (mem, 0)) == LABEL_REF)
+       return \"ldr\\t%0, %1\";
+       
+     if (which_alternative == 0)
+       return \"ldrsb\\t%0, %1\";
+       
+     ops[0] = operands[0];
+     
+     if (GET_CODE (mem) == PLUS)
+       {
+         rtx a = XEXP (mem, 0);
+ 	rtx b = XEXP (mem, 1);
+ 	
+         ops[1] = a;
+         ops[2] = b;
+ 
+         if (GET_CODE (a) == REG)
+ 	  {
+ 	    if (GET_CODE (b) == REG)
+               output_asm_insn (\"ldrsb\\t%0, [%1, %2]\", ops);
+             else if (REGNO (a) == REGNO (ops[0]))
+ 	      {
+                 output_asm_insn (\"ldrb\\t%0, [%1, %2]\", ops);
+ 		output_asm_insn (\"sxtb\\t%0, %0\", ops);
+ 	      }
+ 	    else
+               output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops);
+ 	  }
+         else if (GET_CODE (b) != REG)
+ 	  abort ();
+ 	else
+           {
+             if (REGNO (b) == REGNO (ops[0]))
+ 	      {
+                 output_asm_insn (\"ldrb\\t%0, [%2, %1]\", ops);
+ 		output_asm_insn (\"sxtb\\t%0, %0\", ops);
+ 	      }
+ 	    else
+               output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops);
+           }
+       }
+     else if (GET_CODE (mem) == REG && REGNO (ops[0]) == REGNO (mem))
+       {
+         output_asm_insn (\"ldrb\\t%0, [%0, #0]\", ops);
+ 	output_asm_insn (\"sxtb\\t%0, %0\", ops);
+       }
+     else
+       {
+         ops[1] = mem;
+         ops[2] = const0_rtx;
+ 	
+         output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops);
+       }
+     return \"\";
+   }"
+   [(set_attr "length" "2,2,4")
+    (set_attr "type" "alu_shift,load_byte,load_byte")
+    (set_attr "pool_range" "*,32,32")]
  )
  
  (define_expand "extendsfdf2"


More information about the Gcc-patches mailing list