new ARM shift pattern for double

Nicolas Pitre nico@cam.org
Fri Nov 7 01:49:00 GMT 2003


This patch is two fold:

1) provide better shift patterns for DI values when the shift count is
   const 1.

2) prevent using iwmmxt insns (or cirrus in the ashldi3 case) for shifting 
   DI values when shift count is constant since the default strategy does
   a better job already as arguments don't have to be moved back and 
   forth between normal and coprocessor regs.

Ideally neither 1 nor 2 should happen if the value to shift is known already
siting in an iwmmxt/cirrus register, but since pattern matching happens
before register allocation this doesn't seem to be simple.  So this patch
assume it's not which is by far the common case anyway.

There used to be a ashldi3 template mainly for use with the cirrus pattern
before but I'm failing to find a reason for its presence.  The other iwmmxt
patterns didn't seem to need such construct at all.

Testing and inspection of generated code for cirrus, iwmmxt and plain ARM
targets with various optimization levels show desired effect.


<date>  Nicolas Pitre <nico@cam.org>

	* config/arm/arm.md (ashldi3, arm_ashldi3_1bit, ashrdi3,
	arm_ashrdi3_1bit, lshrdi3, arm_lshrdi3_1bit): New patterns.
	* config/arm/iwmmxt.md (ashrdi3_iwmmxt): Renamed from ashrdi3.
	(lshrdi3_iwmmxt): Renamed from lshrdi3.
	* config/arm/arm.c (IWMMXT_BUILTIN2): Renamed argument accordingly.

Index: config/arm/arm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.c,v
retrieving revision 1.305
diff -u -r1.305 arm.c
--- config/arm/arm.c	30 Oct 2003 10:26:04 -0000	1.305
+++ config/arm/arm.c	6 Nov 2003 22:03:25 -0000
@@ -10560,13 +10560,13 @@
   IWMMXT_BUILTIN2 (lshrv2si3_di,    WSRLW)
   IWMMXT_BUILTIN2 (lshrv2si3,       WSRLWI)
   IWMMXT_BUILTIN2 (lshrdi3_di,      WSRLD)
-  IWMMXT_BUILTIN2 (lshrdi3,         WSRLDI)
+  IWMMXT_BUILTIN2 (lshrdi3_iwmmxt,  WSRLDI)
   IWMMXT_BUILTIN2 (ashrv4hi3_di,    WSRAH)
   IWMMXT_BUILTIN2 (ashrv4hi3,       WSRAHI)
   IWMMXT_BUILTIN2 (ashrv2si3_di,    WSRAW)
   IWMMXT_BUILTIN2 (ashrv2si3,       WSRAWI)
   IWMMXT_BUILTIN2 (ashrdi3_di,      WSRAD)
-  IWMMXT_BUILTIN2 (ashrdi3,         WSRADI)
+  IWMMXT_BUILTIN2 (ashrdi3_iwmmxt,  WSRADI)
   IWMMXT_BUILTIN2 (rorv4hi3_di,     WRORH)
   IWMMXT_BUILTIN2 (rorv4hi3,        WRORHI)
   IWMMXT_BUILTIN2 (rorv2si3_di,     WRORW)
Index: config/arm/arm.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/arm.md,v
retrieving revision 1.145
diff -u -r1.145 arm.md
--- config/arm/arm.md	24 Oct 2003 09:25:30 -0000	1.145
+++ config/arm/arm.md	6 Nov 2003 22:03:40 -0000
@@ -2376,6 +2376,41 @@
 
 ;; Shift and rotation insns
 
+(define_expand "ashldi3"
+  [(set (match_operand:DI            0 "s_register_operand" "")
+        (ashift:DI (match_operand:DI 1 "s_register_operand" "")
+                   (match_operand:SI 2 "reg_or_int_operand" "")))]
+  "TARGET_ARM"
+  "
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      if ((HOST_WIDE_INT) INTVAL (operands[2]) == 1)
+        {
+          emit_insn (gen_arm_ashldi3_1bit (operands[0], operands[1]));
+          DONE;
+        }
+        /* Ideally we shouldn't fail here if we could know that operands[1] 
+           ends up already living in an iwmmxt register. Otherwise it's
+           cheaper to have the alternate code being generated than moving
+           values to iwmmxt regs and back. */
+        FAIL;
+    }
+  else if (!TARGET_REALLY_IWMMXT && !TARGET_CIRRUS)
+    FAIL;
+  "
+)
+
+(define_insn "arm_ashldi3_1bit"
+  [(set (match_operand:DI            0 "s_register_operand" "=&r,r")
+        (ashift:DI (match_operand:DI 1 "s_register_operand" "?r,0")
+                   (const_int 1)))
+   (clobber (reg:CC CC_REGNUM))]
+  "TARGET_ARM"
+  "movs\\t%Q0, %Q1, asl #1\;adc\\t%R0, %R1, %R1"
+  [(set_attr "conds" "clob")
+   (set_attr "length" "8")]
+)
+
 (define_expand "ashlsi3"
   [(set (match_operand:SI            0 "s_register_operand" "")
 	(ashift:SI (match_operand:SI 1 "s_register_operand" "")
@@ -2400,6 +2435,41 @@
   [(set_attr "length" "2")]
 )
 
+(define_expand "ashrdi3"
+  [(set (match_operand:DI              0 "s_register_operand" "")
+        (ashiftrt:DI (match_operand:DI 1 "s_register_operand" "")
+                     (match_operand:SI 2 "reg_or_int_operand" "")))]
+  "TARGET_ARM"
+  "
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      if ((HOST_WIDE_INT) INTVAL (operands[2]) == 1)
+        {
+          emit_insn (gen_arm_ashrdi3_1bit (operands[0], operands[1]));
+          DONE;
+        }
+        /* Ideally we shouldn't fail here if we could know that operands[1] 
+           ends up already living in an iwmmxt register. Otherwise it's
+           cheaper to have the alternate code being generated than moving
+           values to iwmmxt regs and back. */
+        FAIL;
+    }
+  else if (!TARGET_REALLY_IWMMXT)
+    FAIL;
+  "
+)
+
+(define_insn "arm_ashrdi3_1bit"
+  [(set (match_operand:DI              0 "s_register_operand" "=&r,r")
+        (ashiftrt:DI (match_operand:DI 1 "s_register_operand" "?r,0")
+                     (const_int 1)))
+   (clobber (reg:CC CC_REGNUM))]
+  "TARGET_ARM"
+  "movs\\t%R0, %R1, asr #1\;mov\\t%Q0, %Q1, rrx"
+  [(set_attr "conds" "clob")
+   (set_attr "length" "8")]
+)
+
 (define_expand "ashrsi3"
   [(set (match_operand:SI              0 "s_register_operand" "")
 	(ashiftrt:SI (match_operand:SI 1 "s_register_operand" "")
@@ -2421,6 +2491,41 @@
   [(set_attr "length" "2")]
 )
 
+(define_expand "lshrdi3"
+  [(set (match_operand:DI              0 "s_register_operand" "")
+        (lshiftrt:DI (match_operand:DI 1 "s_register_operand" "")
+                     (match_operand:SI 2 "reg_or_int_operand" "")))]
+  "TARGET_ARM"
+  "
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      if ((HOST_WIDE_INT) INTVAL (operands[2]) == 1)
+        {
+          emit_insn (gen_arm_lshrdi3_1bit (operands[0], operands[1]));
+          DONE;
+        }
+        /* Ideally we shouldn't fail here if we could know that operands[1] 
+           ends up already living in an iwmmxt register. Otherwise it's
+           cheaper to have the alternate code being generated than moving
+           values to iwmmxt regs and back. */
+        FAIL;
+    }
+  else if (!TARGET_REALLY_IWMMXT)
+    FAIL;
+  "
+)
+
+(define_insn "arm_lshrdi3_1bit"
+  [(set (match_operand:DI              0 "s_register_operand" "=&r,r")
+        (lshiftrt:DI (match_operand:DI 1 "s_register_operand" "?r,0")
+                     (const_int 1)))
+   (clobber (reg:CC CC_REGNUM))]
+  "TARGET_ARM"
+  "movs\\t%R0, %R1, lsr #1\;mov\\t%Q0, %Q1, rrx"
+  [(set_attr "conds" "clob")
+   (set_attr "length" "8")]
+)
+
 (define_expand "lshrsi3"
   [(set (match_operand:SI              0 "s_register_operand" "")
 	(lshiftrt:SI (match_operand:SI 1 "s_register_operand" "")
@@ -2489,19 +2594,6 @@
   "TARGET_THUMB"
   "ror\\t%0, %0, %2"
   [(set_attr "length" "2")]
-)
-
-(define_expand "ashldi3"
-  [(set (match_operand:DI            0 "s_register_operand" "")
-	(ashift:DI (match_operand:DI 1 "general_operand"    "")
-		   (match_operand:SI 2 "general_operand"    "")))]
-  "TARGET_ARM && (TARGET_IWMMXT || TARGET_CIRRUS)"
-  "
-  if (! s_register_operand (operands[1], DImode))
-    operands[1] = copy_to_mode_reg (DImode, operands[1]);
-  if (! s_register_operand (operands[2], SImode))
-    operands[2] = copy_to_mode_reg (SImode, operands[2]);
-  "
 )
 
 (define_insn "*arm_shiftsi3"
Index: config/arm/iwmmxt.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/arm/iwmmxt.md,v
retrieving revision 1.3
diff -u -r1.3 iwmmxt.md
--- config/arm/iwmmxt.md	14 Oct 2003 02:17:47 -0000	1.3
+++ config/arm/iwmmxt.md	6 Nov 2003 22:03:42 -0000
@@ -1149,7 +1149,7 @@
   "wsrawg%?\\t%0, %1, %2"
   [(set_attr "predicable" "yes")])
 
-(define_insn "ashrdi3"
+(define_insn "ashrdi3_iwmmxt"
   [(set (match_operand:DI              0 "register_operand" "=y")
 	(ashiftrt:DI (match_operand:DI 1 "register_operand" "y")
 		   (match_operand:SI   2 "register_operand" "z")))]
@@ -1173,7 +1173,7 @@
   "wsrlwg%?\\t%0, %1, %2"
   [(set_attr "predicable" "yes")])
 
-(define_insn "lshrdi3"
+(define_insn "lshrdi3_iwmmxt"
   [(set (match_operand:DI              0 "register_operand" "=y")
 	(lshiftrt:DI (match_operand:DI 1 "register_operand" "y")
 		     (match_operand:SI 2 "register_operand" "z")))]



More information about the Gcc-patches mailing list