diff mbox

More ARM pattern merging

Message ID 4C56A025.9090304@codesourcery.com
State New
Headers show

Commit Message

Bernd Schmidt Aug. 2, 2010, 10:38 a.m. UTC
This deals with the various arith_shift patterns which are needlessly
duplicated in thumb2.md.  Merging them requires that we define attribute
enabled, so we can conditionally enable the correct alternatives.

There was a problem with reload_cse_regs.  Since arith_shiftsi can take
the same form as mulsi3_addsi, when reload_cse_regs tries to replace a
constant operand with a register, arith_shiftsi no longer matches, but
the mla does, so the replacement is validated.  Effect of this patch:

        mov     r2, #4
-       mla     r1, r5, r2, r0
+       add     r1, r0, r5, asl #2

Just guessing, but probably mla is a more expensive operation?

Notes:
- I left thumb2_cmpsi_neg_shiftsi alone for now, as it differs from the
  corresponding arm.md pattern
- Some ARM patterns used rI for the shift amount, corrected to the M,r
  form now used elsewhere.

Regression tested (a slightly earlier version with some different
pattern names) with the usual set of flags on arm-linux.


Bernd
* config/arm/thumb2.md (thumb2_notsi_shiftsi,
	thumbsi_notsi_shiftsi_compare0, thumb2_not_shiftsi_compare0_scratch,
	thumb2_cmpsi_shiftsi, thumb2_cmpsi_shiftsi_swp, thumb2_arith_shiftsi,
	thumb2_arith_shiftsi splitter, thumb2_arith_shiftsi_compare0,
	thumb2_arith_shiftsi_compare0_scratch, thumb2_sub_shiftsi,
	thumb2_sub_shiftsi_compare0, thumb2_sub_shiftsi_compare0_scratch,
	orsi_notsi_si, thumb_orsi_not_shiftsi_si, thumb2_iorsi3): Delete.
	* config/arm/predicates.md (shift_amount_operand): New.
	(mult_operator): New.
	* config/arm/arm.md (attr arch, attr arch_enabled, attr insn_enabled,
	attr enabled): New.
	(orsi_notsi_si, orsi_not_shiftsi_si): New patterns.
	(iorsi3_insn): Renamed from arm_iorsi3.  Handle a new alternative if
	arch matches v6.
	(not_shiftsi): Renamed from arm_notsi_shiftsi.  Handle Thumb2 variant.
	(not_shiftsi_compare0): Likewise, renamed from
	arm_notsi_shiftsi_compare0.
	(not_shiftsi_compare0_scratch): Likweise, renamed from
	arm_notsi_shiftsi_compare0_scratch.
	(cmpsi_shiftsi): Likewise, renamed from arm_cmpsi_shiftsi.
	(cmpsi_shiftsi_swp): Likewise, renamed from arm_cmpsi_shiftsi_swp.
	(arith_shiftsi): Handle Thumb2 variant.  Set insn_enabled attribute
	so that the register alternative is disabled when the shift_operator
	is MULT.  Use "M" as the constraint for constants.
	(arith_shiftsi splitter): Enable for TARGET_32BIT.
	(arith_shiftsi_compare0): Handle Thumb2 variant.  Use "M" as the
	constraint for constants.
	(arith_shiftsi_compare0_scratch): Likewise.
	(sub_shiftsi, sub_shiftsi_compare0, sub_shiftsi_compare0_scratch):
	Handle Thumb2 alternative.

Comments

Richard Earnshaw Aug. 2, 2010, 10:51 a.m. UTC | #1
On Mon, 2010-08-02 at 12:38 +0200, Bernd Schmidt wrote:
> This deals with the various arith_shift patterns which are needlessly
> duplicated in thumb2.md.  Merging them requires that we define attribute
> enabled, so we can conditionally enable the correct alternatives.
> 
> There was a problem with reload_cse_regs.  Since arith_shiftsi can take
> the same form as mulsi3_addsi, when reload_cse_regs tries to replace a
> constant operand with a register, arith_shiftsi no longer matches, but
> the mla does, so the replacement is validated.  Effect of this patch:
> 
>         mov     r2, #4
> -       mla     r1, r5, r2, r0
> +       add     r1, r0, r5, asl #2
> 
> Just guessing, but probably mla is a more expensive operation?
> 
> Notes:
> - I left thumb2_cmpsi_neg_shiftsi alone for now, as it differs from the
>   corresponding arm.md pattern
> - Some ARM patterns used rI for the shift amount, corrected to the M,r
>   form now used elsewhere.
> 
> Regression tested (a slightly earlier version with some different
> pattern names) with the usual set of flags on arm-linux.
> 
> 
> Bernd

I don't think this is right.  ORN is Thumb-2 only, it's not available in
ARM state.

Also, orsi_notsi_si should be anonymous (though it incorrectly wasn't
marked so before either).

R.
Bernd Schmidt Aug. 2, 2010, 10:54 a.m. UTC | #2
On 08/02/2010 12:51 PM, Richard Earnshaw wrote:
> I don't think this is right.  ORN is Thumb-2 only, it's not available in
> ARM state.

Looks like I misread the docs.  Do you want it kept in thumb2.md?  I can
just drop that part of the patch or use "t2" rather than "v6" for it in
the iorsi pattern.


Bernd
Richard Earnshaw Aug. 2, 2010, 10:56 a.m. UTC | #3
On Mon, 2010-08-02 at 12:54 +0200, Bernd Schmidt wrote:
> On 08/02/2010 12:51 PM, Richard Earnshaw wrote:
> > I don't think this is right.  ORN is Thumb-2 only, it's not available in
> > ARM state.
> 
> Looks like I misread the docs.  Do you want it kept in thumb2.md?  I can
> just drop that part of the patch or use "t2" rather than "v6" for it in
> the iorsi pattern.
> 
> 
> Bernd

I think merging is a good thing provided it doesn't degrade code
generation when the variant is unavailable.

R.
Ramana Radhakrishnan Aug. 2, 2010, 10:58 a.m. UTC | #4
On Mon, 2010-08-02 at 12:38 +0200, Bernd Schmidt wrote:

> There was a problem with reload_cse_regs.  Since arith_shiftsi can take
> the same form as mulsi3_addsi, when reload_cse_regs tries to replace a
> constant operand with a register, arith_shiftsi no longer matches, but
> the mla does, so the replacement is validated.  Effect of this patch:
> 
>         mov     r2, #4
> -       mla     r1, r5, r2, r0
> +       add     r1, r0, r5, asl #2
> 
> Just guessing, but probably mla is a more expensive operation?

Yes, mla is definitely more expensive than the add with shift.


cheers
Ramana
diff mbox

Patch

Index: config/arm/thumb2.md
===================================================================
--- config/arm/thumb2.md.orig
+++ config/arm/thumb2.md
@@ -120,47 +120,6 @@ 
    (set_attr "length" "10,10,14")]
 )
 
-(define_insn "*thumb2_notsi_shiftsi"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
-	(not:SI (match_operator:SI 3 "shift_operator"
-		 [(match_operand:SI 1 "s_register_operand" "r")
-		  (match_operand:SI 2 "const_int_operand"  "M")])))]
-  "TARGET_THUMB2"
-  "mvn%?\\t%0, %1%S3"
-  [(set_attr "predicable" "yes")
-   (set_attr "shift" "1")
-   (set_attr "type" "alu_shift")]
-)
-
-(define_insn "*thumb2_notsi_shiftsi_compare0"
-  [(set (reg:CC_NOOV CC_REGNUM)
-	(compare:CC_NOOV (not:SI (match_operator:SI 3 "shift_operator"
-			  [(match_operand:SI 1 "s_register_operand" "r")
-			   (match_operand:SI 2 "const_int_operand"  "M")]))
-			 (const_int 0)))
-   (set (match_operand:SI 0 "s_register_operand" "=r")
-	(not:SI (match_op_dup 3 [(match_dup 1) (match_dup 2)])))]
-  "TARGET_THUMB2"
-  "mvn%.\\t%0, %1%S3"
-  [(set_attr "conds" "set")
-   (set_attr "shift" "1")
-   (set_attr "type" "alu_shift")]
-)
-
-(define_insn "*thumb2_not_shiftsi_compare0_scratch"
-  [(set (reg:CC_NOOV CC_REGNUM)
-	(compare:CC_NOOV (not:SI (match_operator:SI 3 "shift_operator"
-			  [(match_operand:SI 1 "s_register_operand" "r")
-			   (match_operand:SI 2 "const_int_operand"  "M")]))
-			 (const_int 0)))
-   (clobber (match_scratch:SI 0 "=r"))]
-  "TARGET_THUMB2"
-  "mvn%.\\t%0, %1%S3"
-  [(set_attr "conds" "set")
-   (set_attr "shift" "1")
-   (set_attr "type" "alu_shift")]
-)
-
 ;; Thumb-2 does not have rsc, so use a clever trick with shifter operands.
 (define_insn "*thumb2_negdi2"
   [(set (match_operand:DI         0 "s_register_operand" "=&r,r")
@@ -260,32 +219,6 @@ 
    (set_attr "neg_pool_range" "*,*,*,250")]
 )
 
-(define_insn "*thumb2_cmpsi_shiftsi"
-  [(set (reg:CC CC_REGNUM)
-	(compare:CC (match_operand:SI   0 "s_register_operand" "r")
-		    (match_operator:SI  3 "shift_operator"
-		     [(match_operand:SI 1 "s_register_operand" "r")
-		      (match_operand:SI 2 "const_int_operand"  "M")])))]
-  "TARGET_THUMB2"
-  "cmp%?\\t%0, %1%S3"
-  [(set_attr "conds" "set")
-   (set_attr "shift" "1")
-   (set_attr "type" "alu_shift")]
-)
-
-(define_insn "*thumb2_cmpsi_shiftsi_swp"
-  [(set (reg:CC_SWP CC_REGNUM)
-	(compare:CC_SWP (match_operator:SI 3 "shift_operator"
-			 [(match_operand:SI 1 "s_register_operand" "r")
-			  (match_operand:SI 2 "const_int_operand" "M")])
-			(match_operand:SI 0 "s_register_operand" "r")))]
-  "TARGET_THUMB2"
-  "cmp%?\\t%0, %1%S3"
-  [(set_attr "conds" "set")
-   (set_attr "shift" "1")
-   (set_attr "type" "alu_shift")]
-)
-
 (define_insn "*thumb2_cmpsi_neg_shiftsi"
   [(set (reg:CC CC_REGNUM)
 	(compare:CC (match_operand:SI 0 "s_register_operand" "r")
@@ -396,122 +329,6 @@ 
 ;; addresses will have the thumb bit set correctly. 
 
 
-;; Patterns to allow combination of arithmetic, cond code and shifts
-
-(define_insn "*thumb2_arith_shiftsi"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
-        (match_operator:SI 1 "shiftable_operator"
-          [(match_operator:SI 3 "shift_operator"
-             [(match_operand:SI 4 "s_register_operand" "r")
-              (match_operand:SI 5 "const_int_operand" "M")])
-           (match_operand:SI 2 "s_register_operand" "rk")]))]
-  "TARGET_THUMB2"
-  "%i1%?\\t%0, %2, %4%S3"
-  [(set_attr "predicable" "yes")
-   (set_attr "shift" "4")
-   (set_attr "type" "alu_shift")]
-)
-
-;; ??? What does this splitter do?  Copied from the ARM version
-(define_split
-  [(set (match_operand:SI 0 "s_register_operand" "")
-	(match_operator:SI 1 "shiftable_operator"
-	 [(match_operator:SI 2 "shiftable_operator"
-	   [(match_operator:SI 3 "shift_operator"
-	     [(match_operand:SI 4 "s_register_operand" "")
-	      (match_operand:SI 5 "const_int_operand" "")])
-	    (match_operand:SI 6 "s_register_operand" "")])
-	  (match_operand:SI 7 "arm_rhs_operand" "")]))
-   (clobber (match_operand:SI 8 "s_register_operand" ""))]
-  "TARGET_32BIT"
-  [(set (match_dup 8)
-	(match_op_dup 2 [(match_op_dup 3 [(match_dup 4) (match_dup 5)])
-			 (match_dup 6)]))
-   (set (match_dup 0)
-	(match_op_dup 1 [(match_dup 8) (match_dup 7)]))]
-  "")
-
-(define_insn "*thumb2_arith_shiftsi_compare0"
-  [(set (reg:CC_NOOV CC_REGNUM)
-        (compare:CC_NOOV (match_operator:SI 1 "shiftable_operator"
-		          [(match_operator:SI 3 "shift_operator"
-		            [(match_operand:SI 4 "s_register_operand" "r")
-		             (match_operand:SI 5 "const_int_operand" "M")])
-		           (match_operand:SI 2 "s_register_operand" "r")])
-			 (const_int 0)))
-   (set (match_operand:SI 0 "s_register_operand" "=r")
-	(match_op_dup 1 [(match_op_dup 3 [(match_dup 4) (match_dup 5)])
-			 (match_dup 2)]))]
-  "TARGET_32BIT"
-  "%i1%.\\t%0, %2, %4%S3"
-  [(set_attr "conds" "set")
-   (set_attr "shift" "4")
-   (set_attr "type" "alu_shift")]
-)
-
-(define_insn "*thumb2_arith_shiftsi_compare0_scratch"
-  [(set (reg:CC_NOOV CC_REGNUM)
-        (compare:CC_NOOV (match_operator:SI 1 "shiftable_operator"
-		          [(match_operator:SI 3 "shift_operator"
-		            [(match_operand:SI 4 "s_register_operand" "r")
-		             (match_operand:SI 5 "const_int_operand" "M")])
-		           (match_operand:SI 2 "s_register_operand" "r")])
-			 (const_int 0)))
-   (clobber (match_scratch:SI 0 "=r"))]
-  "TARGET_THUMB2"
-  "%i1%.\\t%0, %2, %4%S3"
-  [(set_attr "conds" "set")
-   (set_attr "shift" "4")
-   (set_attr "type" "alu_shift")]
-)
-
-(define_insn "*thumb2_sub_shiftsi"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
-	(minus:SI (match_operand:SI 1 "s_register_operand" "r")
-		  (match_operator:SI 2 "shift_operator"
-		   [(match_operand:SI 3 "s_register_operand" "r")
-		    (match_operand:SI 4 "const_int_operand" "M")])))]
-  "TARGET_THUMB2"
-  "sub%?\\t%0, %1, %3%S2"
-  [(set_attr "predicable" "yes")
-   (set_attr "shift" "3")
-   (set_attr "type" "alu_shift")]
-)
-
-(define_insn "*thumb2_sub_shiftsi_compare0"
-  [(set (reg:CC_NOOV CC_REGNUM)
-	(compare:CC_NOOV
-	 (minus:SI (match_operand:SI 1 "s_register_operand" "r")
-		   (match_operator:SI 2 "shift_operator"
-		    [(match_operand:SI 3 "s_register_operand" "r")
-		     (match_operand:SI 4 "const_int_operand" "M")]))
-	 (const_int 0)))
-   (set (match_operand:SI 0 "s_register_operand" "=r")
-	(minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3)
-						 (match_dup 4)])))]
-  "TARGET_THUMB2"
-  "sub%.\\t%0, %1, %3%S2"
-  [(set_attr "conds" "set")
-   (set_attr "shift" "3")
-   (set_attr "type" "alu_shift")]
-)
-
-(define_insn "*thumb2_sub_shiftsi_compare0_scratch"
-  [(set (reg:CC_NOOV CC_REGNUM)
-	(compare:CC_NOOV
-	 (minus:SI (match_operand:SI 1 "s_register_operand" "r")
-		   (match_operator:SI 2 "shift_operator"
-		    [(match_operand:SI 3 "s_register_operand" "r")
-		     (match_operand:SI 4 "const_int_operand" "M")]))
-	 (const_int 0)))
-   (clobber (match_scratch:SI 0 "=r"))]
-  "TARGET_THUMB2"
-  "sub%.\\t%0, %1, %3%S2"
-  [(set_attr "conds" "set")
-   (set_attr "shift" "3")
-   (set_attr "type" "alu_shift")]
-)
-
 (define_insn "*thumb2_and_scc"
   [(set (match_operand:SI 0 "s_register_operand" "=r")
 	(and:SI (match_operator:SI 1 "arm_comparison_operator"
@@ -1365,51 +1182,6 @@ 
    (set_attr "length" "2")]
 )
 
-(define_insn "orsi_notsi_si"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
-	(ior:SI (not:SI (match_operand:SI 2 "s_register_operand" "r"))
-		(match_operand:SI 1 "s_register_operand" "r")))]
-  "TARGET_THUMB2"
-  "orn%?\\t%0, %1, %2"
-  [(set_attr "predicable" "yes")]
-)
-
-(define_insn "*thumb_orsi_not_shiftsi_si"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
-	(ior:SI (not:SI (match_operator:SI 4 "shift_operator"
-			 [(match_operand:SI 2 "s_register_operand" "r")
-			  (match_operand:SI 3 "const_int_operand" "M")]))
-		(match_operand:SI 1 "s_register_operand" "r")))]
-  "TARGET_THUMB2"
-  "orn%?\\t%0, %1, %2%S4"
-  [(set_attr "predicable" "yes")
-   (set_attr "shift" "2")
-   (set_attr "type" "alu_shift")]
-)
-
-(define_insn_and_split "*thumb2_iorsi3"
-  [(set (match_operand:SI         0 "s_register_operand" "=r,r,r")
-	(ior:SI (match_operand:SI 1 "s_register_operand" "r,r,r")
-		(match_operand:SI 2 "reg_or_int_operand" "rI,K,?n")))]
-  "TARGET_THUMB2"
-  "@
-   orr%?\\t%0, %1, %2
-   orn%?\\t%0, %1, #%B2
-   #"
-  "TARGET_THUMB2
-   && GET_CODE (operands[2]) == CONST_INT
-   && !(const_ok_for_arm (INTVAL (operands[2]))
-	|| const_ok_for_arm (~INTVAL (operands[2])))"
-  [(clobber (const_int 0))]
-  "
-  arm_split_constant  (IOR, SImode, curr_insn, 
-	               INTVAL (operands[2]), operands[0], operands[1], 0);
-  DONE;
-  "
-  [(set_attr "length" "4,4,16")
-   (set_attr "predicable" "yes")]
-)
-
 (define_peephole2
   [(set (match_operand:CC_NOOV 0 "cc_register" "")
 	(compare:CC_NOOV (zero_extract:SI
Index: config/arm/predicates.md
===================================================================
--- config/arm/predicates.md.orig
+++ config/arm/predicates.md
@@ -128,6 +128,11 @@ 
   (ior (match_operand 0 "arm_rhs_operand")
        (match_operand 0 "memory_operand")))
 
+(define_predicate "shift_amount_operand"
+  (ior (and (match_test "TARGET_ARM")
+	    (match_operand 0 "s_register_operand"))
+       (match_operand 0 "const_int_operand")))
+
 (define_predicate "arm_add_operand"
   (ior (match_operand 0 "arm_rhs_operand")
        (match_operand 0 "arm_neg_immediate_operand")))
@@ -221,6 +226,10 @@ 
 	    (match_code "ashift,ashiftrt,lshiftrt,rotatert"))
        (match_test "mode == GET_MODE (op)")))
 
+;; True for MULT, to identify which variant of shift_operator is in use.
+(define_special_predicate "mult_operator"
+  (match_code "mult"))
+
 ;; True for operators that have 16-bit thumb variants.  */
 (define_special_predicate "thumb_16bit_operator"
   (match_code "plus,minus,and,ior,xor"))
Index: config/arm/arm.md
===================================================================
--- config/arm/arm.md.orig
+++ config/arm/arm.md
@@ -167,6 +167,59 @@ 
 ; LENGTH of an instruction (in bytes)
 (define_attr "length" "" (const_int 4))
 
+; The architecture which supports the instruction (or alternative).
+; This can be "a" for ARM, "t" for either of the Thumbs, "32" for
+; TARGET_32BIT, "t1" or "t2" to specify a specific Thumb mode.  "v6"
+; for ARM or Thumb-2 with arm_arch6, and nov6 for ARM without
+; arm_arch6.  This attribute is used to compute attribute "enabled",
+; use type "any" to enable an alternative in all cases.
+(define_attr "arch" "any,a,t,32,t1,t2,v6,nov6"
+  (const_string "any"))
+
+(define_attr "arch_enabled" "no,yes"
+  (cond [(eq_attr "arch" "any")
+	 (const_string "yes")
+
+	 (and (eq_attr "arch" "a")
+	      (ne (symbol_ref "TARGET_ARM") (const_int 0)))
+	 (const_string "yes")
+
+	 (and (eq_attr "arch" "t")
+	      (ne (symbol_ref "TARGET_THUMB") (const_int 0)))
+	 (const_string "yes")
+
+	 (and (eq_attr "arch" "t1")
+	      (ne (symbol_ref "TARGET_THUMB1") (const_int 0)))
+	 (const_string "yes")
+
+	 (and (eq_attr "arch" "t2")
+	      (ne (symbol_ref "TARGET_THUMB2") (const_int 0)))
+	 (const_string "yes")
+
+	 (and (eq_attr "arch" "32")
+	      (ne (symbol_ref "TARGET_32BIT") (const_int 0)))
+	 (const_string "yes")
+
+	 (and (eq_attr "arch" "v6")
+	      (ne (symbol_ref "(TARGET_32BIT && arm_arch6)") (const_int 0)))
+	 (const_string "yes")
+
+	 (and (eq_attr "arch" "nov6")
+	      (ne (symbol_ref "(TARGET_32BIT && !arm_arch6)") (const_int 0)))
+	 (const_string "yes")]
+	(const_string "no")))
+
+; Allows an insn to disable certain alternatives for reasons other than
+; arch support.
+(define_attr "insn_enabled" "no,yes"
+  (const_string "yes"))
+
+; Enable all alternatives that are both arch_enabled and insn_enabled.
+(define_attr "enabled" "no,yes"
+  (if_then_else (eq_attr "insn_enabled" "yes")
+		(attr "arch_enabled")
+		(const_string "no")))
+
 ; POOL_RANGE is how far away from a constant pool entry that this insn
 ; can be placed.  If the distance is zero, then this insn will never
 ; reference the pool.
@@ -2699,26 +2752,48 @@ 
   "
 )
 
-(define_insn_and_split "*arm_iorsi3"
-  [(set (match_operand:SI         0 "s_register_operand" "=r,r")
-	(ior:SI (match_operand:SI 1 "s_register_operand" "r,r")
-		(match_operand:SI 2 "reg_or_int_operand" "rI,?n")))]
-  "TARGET_ARM"
+(define_insn "orsi_notsi_si"
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
+	(ior:SI (not:SI (match_operand:SI 2 "s_register_operand" "r"))
+		(match_operand:SI 1 "s_register_operand" "r")))]
+  "TARGET_32BIT && arm_arch6"
+  "orn%?\\t%0, %1, %2"
+  [(set_attr "predicable" "yes")])
+
+(define_insn "*orsi_not_shiftsi_si"
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
+	(ior:SI (not:SI (match_operator:SI 4 "shift_operator"
+			 [(match_operand:SI 2 "s_register_operand" "r")
+			  (match_operand:SI 3 "const_int_operand" "M")]))
+		(match_operand:SI 1 "s_register_operand" "r")))]
+  "TARGET_32BIT && arm_arch6"
+  "orn%?\\t%0, %1, %2%S4"
+  [(set_attr "predicable" "yes")
+   (set_attr "shift" "2")
+   (set_attr "type" "alu_shift")])
+
+(define_insn_and_split "*iorsi3_insn"
+  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
+	(ior:SI (match_operand:SI 1 "s_register_operand" "%r,r,r")
+		(match_operand:SI 2 "reg_or_int_operand" "rI,K,?n")))]
+  "TARGET_32BIT"
   "@
    orr%?\\t%0, %1, %2
+   orn%?\\t%0, %1, #%B2
    #"
-  "TARGET_ARM
+  "TARGET_32BIT
    && GET_CODE (operands[2]) == CONST_INT
-   && !const_ok_for_arm (INTVAL (operands[2]))"
+   && !(const_ok_for_arm (INTVAL (operands[2]))
+        || (arm_arch6 && const_ok_for_arm (~INTVAL (operands[2]))))"
   [(clobber (const_int 0))]
-  "
+{
   arm_split_constant (IOR, SImode, curr_insn, 
                       INTVAL (operands[2]), operands[0], operands[1], 0);
   DONE;
-  "
-  [(set_attr "length" "4,16")
-   (set_attr "predicable" "yes")]
-)
+}
+  [(set_attr "length" "4,4,16")
+   (set_attr "arch" "32,v6,32")
+   (set_attr "predicable" "yes")])
 
 (define_insn "*thumb1_iorsi3_insn"
   [(set (match_operand:SI         0 "register_operand" "=l")
@@ -3486,52 +3561,48 @@ 
    (set_attr "shift" "1")]
 )
 
-(define_insn "*arm_notsi_shiftsi"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+(define_insn "*not_shiftsi"
+  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
 	(not:SI (match_operator:SI 3 "shift_operator"
-		 [(match_operand:SI 1 "s_register_operand" "r")
-		  (match_operand:SI 2 "arm_rhs_operand" "rM")])))]
-  "TARGET_ARM"
+		 [(match_operand:SI 1 "s_register_operand" "r,r")
+		  (match_operand:SI 2 "shift_amount_operand" "M,rM")])))]
+  "TARGET_32BIT"
   "mvn%?\\t%0, %1%S3"
   [(set_attr "predicable" "yes")
    (set_attr "shift" "1")
-   (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
-		      (const_string "alu_shift")
-		      (const_string "alu_shift_reg")))]
-)
+   (set_attr "arch" "32,a")
+   (set_attr "type" "alu_shift,alu_shift_reg")])
 
-(define_insn "*arm_notsi_shiftsi_compare0"
+(define_insn "*not_shiftsi_compare0"
   [(set (reg:CC_NOOV CC_REGNUM)
-	(compare:CC_NOOV (not:SI (match_operator:SI 3 "shift_operator"
-			  [(match_operand:SI 1 "s_register_operand" "r")
-			   (match_operand:SI 2 "arm_rhs_operand" "rM")]))
-			 (const_int 0)))
-   (set (match_operand:SI 0 "s_register_operand" "=r")
+	(compare:CC_NOOV
+	 (not:SI (match_operator:SI 3 "shift_operator"
+		  [(match_operand:SI 1 "s_register_operand" "r,r")
+		   (match_operand:SI 2 "shift_amount_operand" "M,rM")]))
+	 (const_int 0)))
+   (set (match_operand:SI 0 "s_register_operand" "=r,r")
 	(not:SI (match_op_dup 3 [(match_dup 1) (match_dup 2)])))]
-  "TARGET_ARM"
+  "TARGET_32BIT"
   "mvn%.\\t%0, %1%S3"
   [(set_attr "conds" "set")
    (set_attr "shift" "1")
-   (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
-		      (const_string "alu_shift")
-		      (const_string "alu_shift_reg")))]
-)
+   (set_attr "arch" "32,a")
+   (set_attr "type" "alu_shift,alu_shift_reg")])
 
-(define_insn "*arm_not_shiftsi_compare0_scratch"
+(define_insn "*not_shiftsi_compare0_scratch"
   [(set (reg:CC_NOOV CC_REGNUM)
-	(compare:CC_NOOV (not:SI (match_operator:SI 3 "shift_operator"
-			  [(match_operand:SI 1 "s_register_operand" "r")
-			   (match_operand:SI 2 "arm_rhs_operand" "rM")]))
-			 (const_int 0)))
-   (clobber (match_scratch:SI 0 "=r"))]
-  "TARGET_ARM"
+	(compare:CC_NOOV
+	 (not:SI (match_operator:SI 3 "shift_operator"
+		  [(match_operand:SI 1 "s_register_operand" "r,r")
+		   (match_operand:SI 2 "shift_amount_operand" "M,rM")]))
+	 (const_int 0)))
+   (clobber (match_scratch:SI 0 "=r,r"))]
+  "TARGET_32BIT"
   "mvn%.\\t%0, %1%S3"
   [(set_attr "conds" "set")
    (set_attr "shift" "1")
-   (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
-		      (const_string "alu_shift")
-		      (const_string "alu_shift_reg")))]
-)
+   (set_attr "arch" "32,a")
+   (set_attr "type" "alu_shift,alu_shift_reg")])
 
 ;; We don't really have extzv, but defining this using shifts helps
 ;; to reduce register pressure later on.
@@ -7005,35 +7076,31 @@ 
   [(set_attr "conds" "set")]
 )
 
-(define_insn "*arm_cmpsi_shiftsi"
+(define_insn "*cmpsi_shiftsi"
   [(set (reg:CC CC_REGNUM)
-	(compare:CC (match_operand:SI   0 "s_register_operand" "r")
+	(compare:CC (match_operand:SI   0 "s_register_operand" "r,r")
 		    (match_operator:SI  3 "shift_operator"
-		     [(match_operand:SI 1 "s_register_operand" "r")
-		      (match_operand:SI 2 "arm_rhs_operand"    "rM")])))]
-  "TARGET_ARM"
+		     [(match_operand:SI 1 "s_register_operand" "r,r")
+		      (match_operand:SI 2 "shift_amount_operand" "M,rM")])))]
+  "TARGET_32BIT"
   "cmp%?\\t%0, %1%S3"
   [(set_attr "conds" "set")
    (set_attr "shift" "1")
-   (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
-		      (const_string "alu_shift")
-		      (const_string "alu_shift_reg")))]
-)
+   (set_attr "arch" "32,a")
+   (set_attr "type" "alu_shift,alu_shift_reg")])
 
-(define_insn "*arm_cmpsi_shiftsi_swp"
+(define_insn "*cmpsi_shiftsi_swp"
   [(set (reg:CC_SWP CC_REGNUM)
 	(compare:CC_SWP (match_operator:SI 3 "shift_operator"
-			 [(match_operand:SI 1 "s_register_operand" "r")
-			  (match_operand:SI 2 "reg_or_int_operand" "rM")])
-			(match_operand:SI 0 "s_register_operand" "r")))]
-  "TARGET_ARM"
+			 [(match_operand:SI 1 "s_register_operand" "r,r")
+			  (match_operand:SI 2 "shift_amount_operand" "M,rM")])
+			(match_operand:SI 0 "s_register_operand" "r,r")))]
+  "TARGET_32BIT"
   "cmp%?\\t%0, %1%S3"
   [(set_attr "conds" "set")
    (set_attr "shift" "1")
-   (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
-		      (const_string "alu_shift")
-		      (const_string "alu_shift_reg")))]
-)
+   (set_attr "arch" "32,a")
+   (set_attr "type" "alu_shift,alu_shift_reg")])
 
 (define_insn "*arm_cmpsi_negshiftsi_si"
   [(set (reg:CC_Z CC_REGNUM)
@@ -8385,20 +8452,28 @@ 
 ;; Patterns to allow combination of arithmetic, cond code and shifts
 
 (define_insn "*arith_shiftsi"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
         (match_operator:SI 1 "shiftable_operator"
           [(match_operator:SI 3 "shift_operator"
-             [(match_operand:SI 4 "s_register_operand" "r")
-              (match_operand:SI 5 "reg_or_int_operand" "rI")])
-           (match_operand:SI 2 "s_register_operand" "rk")]))]
-  "TARGET_ARM"
+             [(match_operand:SI 4 "s_register_operand" "r,r")
+              (match_operand:SI 5 "shift_amount_operand" "M,r")])
+           (match_operand:SI 2 "s_register_operand" "rk,rk")]))]
+  "TARGET_32BIT"
   "%i1%?\\t%0, %2, %4%S3"
   [(set_attr "predicable" "yes")
    (set_attr "shift" "4")
-   (set (attr "type") (if_then_else (match_operand 5 "const_int_operand" "")
-		      (const_string "alu_shift")
-		      (const_string "alu_shift_reg")))]
-)
+   (set_attr "arch" "32,a")
+   ;; We have to make sure to disable the second alternative if
+   ;; the shift_operator is MULT, since otherwise the insn will
+   ;; also match a multiply_accumulate pattern and validate_change
+   ;; will allow a replacement of the constant with a register
+   ;; despite the checks done in shift_operator.
+   (set_attr_alternative "insn_enabled"
+			 [(const_string "yes")
+			  (if_then_else
+			   (match_operand:SI 3 "mult_operator" "")
+			   (const_string "no") (const_string "yes"))])
+   (set_attr "type" "alu_shift,alu_shift_reg")])
 
 (define_split
   [(set (match_operand:SI 0 "s_register_operand" "")
@@ -8410,7 +8485,7 @@ 
 	    (match_operand:SI 6 "s_register_operand" "")])
 	  (match_operand:SI 7 "arm_rhs_operand" "")]))
    (clobber (match_operand:SI 8 "s_register_operand" ""))]
-  "TARGET_ARM"
+  "TARGET_32BIT"
   [(set (match_dup 8)
 	(match_op_dup 2 [(match_op_dup 3 [(match_dup 4) (match_dup 5)])
 			 (match_dup 6)]))
@@ -8420,95 +8495,86 @@ 
 
 (define_insn "*arith_shiftsi_compare0"
   [(set (reg:CC_NOOV CC_REGNUM)
-        (compare:CC_NOOV (match_operator:SI 1 "shiftable_operator"
-		          [(match_operator:SI 3 "shift_operator"
-		            [(match_operand:SI 4 "s_register_operand" "r")
-		             (match_operand:SI 5 "reg_or_int_operand" "rI")])
-		           (match_operand:SI 2 "s_register_operand" "r")])
-			 (const_int 0)))
-   (set (match_operand:SI 0 "s_register_operand" "=r")
+        (compare:CC_NOOV
+	 (match_operator:SI 1 "shiftable_operator"
+	  [(match_operator:SI 3 "shift_operator"
+	    [(match_operand:SI 4 "s_register_operand" "r,r")
+	     (match_operand:SI 5 "shift_amount_operand" "M,r")])
+	   (match_operand:SI 2 "s_register_operand" "r,r")])
+	 (const_int 0)))
+   (set (match_operand:SI 0 "s_register_operand" "=r,r")
 	(match_op_dup 1 [(match_op_dup 3 [(match_dup 4) (match_dup 5)])
 			 (match_dup 2)]))]
-  "TARGET_ARM"
+  "TARGET_32BIT"
   "%i1%.\\t%0, %2, %4%S3"
   [(set_attr "conds" "set")
    (set_attr "shift" "4")
-   (set (attr "type") (if_then_else (match_operand 5 "const_int_operand" "")
-		      (const_string "alu_shift")
-		      (const_string "alu_shift_reg")))]
-)
+   (set_attr "arch" "32,a")
+   (set_attr "type" "alu_shift,alu_shift_reg")])
 
 (define_insn "*arith_shiftsi_compare0_scratch"
   [(set (reg:CC_NOOV CC_REGNUM)
-        (compare:CC_NOOV (match_operator:SI 1 "shiftable_operator"
-		          [(match_operator:SI 3 "shift_operator"
-		            [(match_operand:SI 4 "s_register_operand" "r")
-		             (match_operand:SI 5 "reg_or_int_operand" "rI")])
-		           (match_operand:SI 2 "s_register_operand" "r")])
-			 (const_int 0)))
-   (clobber (match_scratch:SI 0 "=r"))]
-  "TARGET_ARM"
+        (compare:CC_NOOV
+	 (match_operator:SI 1 "shiftable_operator"
+	  [(match_operator:SI 3 "shift_operator"
+	    [(match_operand:SI 4 "s_register_operand" "r,r")
+	     (match_operand:SI 5 "shift_amount_operand" "M,r")])
+	   (match_operand:SI 2 "s_register_operand" "r,r")])
+	 (const_int 0)))
+   (clobber (match_scratch:SI 0 "=r,r"))]
+  "TARGET_32BIT"
   "%i1%.\\t%0, %2, %4%S3"
   [(set_attr "conds" "set")
    (set_attr "shift" "4")
-   (set (attr "type") (if_then_else (match_operand 5 "const_int_operand" "")
-		      (const_string "alu_shift")
-		      (const_string "alu_shift_reg")))]
-)
+   (set_attr "arch" "32,a")
+   (set_attr "type" "alu_shift,alu_shift_reg")])
 
 (define_insn "*sub_shiftsi"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
-	(minus:SI (match_operand:SI 1 "s_register_operand" "r")
+  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+	(minus:SI (match_operand:SI 1 "s_register_operand" "r,r")
 		  (match_operator:SI 2 "shift_operator"
-		   [(match_operand:SI 3 "s_register_operand" "r")
-		    (match_operand:SI 4 "reg_or_int_operand" "rM")])))]
-  "TARGET_ARM"
+		   [(match_operand:SI 3 "s_register_operand" "r,r")
+		    (match_operand:SI 4 "shift_amount_operand" "M,r")])))]
+  "TARGET_32BIT"
   "sub%?\\t%0, %1, %3%S2"
   [(set_attr "predicable" "yes")
    (set_attr "shift" "3")
-   (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "")
-		      (const_string "alu_shift")
-		      (const_string "alu_shift_reg")))]
-)
+   (set_attr "arch" "32,a")
+   (set_attr "type" "alu_shift,alu_shift_reg")])
 
 (define_insn "*sub_shiftsi_compare0"
   [(set (reg:CC_NOOV CC_REGNUM)
 	(compare:CC_NOOV
-	 (minus:SI (match_operand:SI 1 "s_register_operand" "r")
+	 (minus:SI (match_operand:SI 1 "s_register_operand" "r,r")
 		   (match_operator:SI 2 "shift_operator"
-		    [(match_operand:SI 3 "s_register_operand" "r")
-		     (match_operand:SI 4 "reg_or_int_operand" "rM")]))
+		    [(match_operand:SI 3 "s_register_operand" "r,r")
+		     (match_operand:SI 4 "shift_amount_operand" "M,rM")]))
 	 (const_int 0)))
-   (set (match_operand:SI 0 "s_register_operand" "=r")
-	(minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3)
-						 (match_dup 4)])))]
-  "TARGET_ARM"
+   (set (match_operand:SI 0 "s_register_operand" "=r,r")
+	(minus:SI (match_dup 1)
+		  (match_op_dup 2 [(match_dup 3) (match_dup 4)])))]
+  "TARGET_32BIT"
   "sub%.\\t%0, %1, %3%S2"
   [(set_attr "conds" "set")
    (set_attr "shift" "3")
-   (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "")
-		      (const_string "alu_shift")
-		      (const_string "alu_shift_reg")))]
-)
+   (set_attr "arch" "32,a")
+   (set_attr "type" "alu_shift,alu_shift_reg")])
 
 (define_insn "*sub_shiftsi_compare0_scratch"
   [(set (reg:CC_NOOV CC_REGNUM)
 	(compare:CC_NOOV
-	 (minus:SI (match_operand:SI 1 "s_register_operand" "r")
+	 (minus:SI (match_operand:SI 1 "s_register_operand" "r,r")
 		   (match_operator:SI 2 "shift_operator"
-		    [(match_operand:SI 3 "s_register_operand" "r")
-		     (match_operand:SI 4 "reg_or_int_operand" "rM")]))
+		    [(match_operand:SI 3 "s_register_operand" "r,r")
+		     (match_operand:SI 4 "shift_amount_operand" "M,rM")]))
 	 (const_int 0)))
-   (clobber (match_scratch:SI 0 "=r"))]
-  "TARGET_ARM"
+   (clobber (match_scratch:SI 0 "=r,r"))]
+  "TARGET_32BIT"
   "sub%.\\t%0, %1, %3%S2"
   [(set_attr "conds" "set")
    (set_attr "shift" "3")
-   (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "")
-		      (const_string "alu_shift")
-		      (const_string "alu_shift_reg")))]
-)
-
+   (set_attr "arch" "32,a")
+   (set_attr "type" "alu_shift,alu_shift_reg")])
 
 
 (define_insn "*and_scc"
Index: postreload.c
===================================================================
--- postreload.c.orig
+++ postreload.c
@@ -573,6 +573,7 @@  reload_cse_simplify_operands (rtx insn, 
 		     alternative yet and the operand being replaced is not
 		     a cheap CONST_INT.  */
 		  if (op_alt_regno[i][j] == -1
+		      && recog_data.alternative_enabled_p[j]
 		      && reg_fits_class_p (testreg, rclass, 0, mode)
 		      && (!CONST_INT_P (recog_data.operand[i])
 			  || (rtx_cost (recog_data.operand[i], SET,