Index: gcc-4.3.6/gcc/config/arm/arm.opt
===================================================================
--- gcc-4.3.6.orig/gcc/config/arm/arm.opt	2013-07-10 21:20:49.000000000 +0200
+++ gcc-4.3.6/gcc/config/arm/arm.opt	2013-07-11 01:40:10.000000000 +0200
@@ -70,7 +70,12 @@
 ; -mno-cirrus-ashldi3 for testing
 mcirrus-ashldi3
 Target Report Mask(CIRRUS_ASHLDI3) Undocumented Init(1)
-Cirrus: Enable shifting 64-bit integers by a variable number of places in the MaverickCrunch unit
+Cirrus: Enable shifting 64-bit integers left by a variable number of places in the MaverickCrunch unit
+
+; -mno-cirrus-ashrdi3 for testing
+mcirrus-ashrdi3
+Target Report Mask(CIRRUS_ASHRDI3) Undocumented Init(1)
+Cirrus: Enable arithmetic shift right of 64-bit integers by a variable number of places in the MaverickCrunch unit
 
 mcpu=
 Target RejectNegative Joined
Index: gcc-4.3.6/gcc/config/arm/cirrus.md
===================================================================
--- gcc-4.3.6.orig/gcc/config/arm/cirrus.md	2013-07-10 21:20:49.000000000 +0200
+++ gcc-4.3.6/gcc/config/arm/cirrus.md	2013-07-11 01:36:29.000000000 +0200
@@ -260,6 +260,11 @@
 ; Solution: do the 0-31 bit shift, then apply a 32-bit shift:
 ;    and	%s3, %s2, #31
 ;    cfrshl64	%V1, %V0, %s3	; writes V0
+;    nop			; Avoid erratum 2
+;    ; Special case: when shift count == 64, result == 0
+;    cmp	%s2, #64
+;    cfsub64ge	mvdx0, %V0,%V0,%V0
+;    ; Now do the other 32 bit shift if the arg was 32..63
 ;    ands	%s3, %s2, #32
 ;    cfsh64ne	%V0, %V0, #16
 ;    cfsh64ne	%V0, %V0, #16
@@ -272,12 +277,40 @@
    (clobber (reg:CC CC_REGNUM))]
   "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_MAVERICK
 	&& TARGET_CIRRUS_DI && TARGET_CIRRUS_ASHLDI3"
-  "and\\t%s3, %s2, #31\;cfrshl64\\t%V1, %V0, %s3\;ands\\t%s3, %s2, #32\;cfsh64ne\\t%V0, %V0, #16\;cfsh64ne\\t%V0, %V0, #16"
+  "and\\t%s3, %s2, #31\;cfrshl64\\t%V1, %V0, %s3\;nop\;cmp\\t%s2,#64\;cfsub64ge\\t%V0,%V0,%V0\;ands\\t%s3, %s2, #32\;cfsh64ne\\t%V0, %V0, #16\;cfsh64ne\\t%V0, %V0, #16"
   [(set_attr "type" "farith")
-   (set_attr "length" "20")
+   (set_attr "length" "32")
    (set_attr "cirrus" "normal")]
 )
 
+; Arithmetic shift right, by shifting left by a negative amount.
+;    // First, shift by 0..32 places, then do the other 32 if required
+;    negs	%s3, %s2	; 1..32 -> -1..-32, 0->0
+;    orrne	%s3, #32	; -63..-33 -> -31..-1, 0->0
+;    cfrshl64	%V1, %V0, %s3	; writes V0,
+;    nop			; Avoid erratum 2
+;    cmp	%s2, #32	; If count >= 32
+;    cfsh64gt	%V0, %V0, #-32	; do the other 32 bits of shift
+
+(define_insn "cirrus_ashrdi3"
+  [(set (match_operand:DI              0 "cirrus_fp_register" "=v")
+	(ashiftrt:DI (match_operand:DI 1 "cirrus_fp_register"  "v")
+		     (match_operand:SI 2 "register_operand"    "r")))
+   (clobber (match_scratch:SI 3 "=r"))
+   (clobber (reg:CC CC_REGNUM))]
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_MAVERICK
+	&& TARGET_CIRRUS_DI && TARGET_CIRRUS_ASHRDI3"
+  "negs\\t%s3, %s2, #31\;orrne\\t%s3, #32\;cfrshl64\\t%V1, %V0, %s3\;nop\;cmp\\t%s2, #32\;cfsh64gt\\t%V0, %V0, #-32"
+  [(set_attr "type" "farith")
+   (set_attr "length" "24")
+   (set_attr "cirrus" "normal")]
+)
+
+; The Crunch always does arithmetic right shifts, duplicating the top bit,
+; even if you set the Unsigned Integer bit in the DSPCS register.
+; Inventing a logical right shift from an arithmetic one is probably possible
+; but...
+
 (define_insn "cirrus_ashldi_const"
   [(set (match_operand:DI            0 "cirrus_fp_register" "=v")
 	(ashift:DI (match_operand:DI 1 "cirrus_fp_register"  "v")
