OSDN Git Service

* arm.md (movqi): On thumb when optimizing, handle loading from
[pf3gnuchains/gcc-fork.git] / gcc / config / arm / arm.md
index 705d22d..783fab0 100644 (file)
@@ -1,26 +1,26 @@
 ;;- Machine description for ARM for GNU compiler
 ;;  Copyright 1991, 1993, 1994, 1995, 1996, 1996, 1997, 1998, 1999, 2000,
-;;  2001, 2002, 2003  Free Software Foundation, Inc.
+;;  2001, 2002, 2003, 2004, 2005  Free Software Foundation, Inc.
 ;;  Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl)
 ;;  and Martin Simmons (@harleqn.co.uk).
 ;;  More major hacks by Richard Earnshaw (rearnsha@arm.com).
 
-;; This file is part of GNU CC.
+;; This file is part of GCC.
 
-;; GNU CC is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
-;; any later version.
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published
+;; by the Free Software Foundation; either version 2, or (at your
+;; option) any later version.
 
-;; GNU CC is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
+;; GCC is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+;; License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU CC; see the file COPYING.  If not, write to
-;; the Free Software Foundation, 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; along with GCC; see the file COPYING.  If not, write to
+;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
 
 
 ;; Register numbers
 (define_constants
-  [(IP_REGNUM      12)         ; Scratch register
+  [(R0_REGNUM        0)                ; First CORE register
+   (IP_REGNUM      12)         ; Scratch register
    (SP_REGNUM      13)         ; Stack pointer
    (LR_REGNUM       14)                ; Return address register
    (PC_REGNUM      15)         ; Program counter
    (CC_REGNUM       24)                ; Condition code pseudo register
-   (LAST_ARM_REGNUM 15)
+   (LAST_ARM_REGNUM 15)                ;
+   (FPA_F0_REGNUM   16)                ; FIRST_FPA_REGNUM
+   (FPA_F7_REGNUM   23)                ; LAST_FPA_REGNUM
+  ]
+)
+;; 3rd operand to select_dominance_cc_mode
+(define_constants
+  [(DOM_CC_X_AND_Y  0)
+   (DOM_CC_NX_OR_Y  1)
+   (DOM_CC_X_OR_Y   2)
   ]
 )
 
    (UNSPEC_PIC_SYM   3) ; A symbol that has been treated properly for pic
                        ;   usage, that is, we will add the pic_register
                        ;   value to it before trying to dereference it.
-   (UNSPEC_PRLG_STK  4) ; A special barrier that prevents frame accesses 
+   (UNSPEC_PIC_BASE  4)        ; Adding the PC value to the offset to the
+                       ;   GLOBAL_OFFSET_TABLE.  The operation is fully
+                       ;   described by the RTL but must be wrapped to
+                       ;   prevent combine from trying to rip it apart.
+   (UNSPEC_PRLG_STK  5) ; A special barrier that prevents frame accesses 
                        ;   being scheduled before the stack adjustment insn.
    (UNSPEC_PROLOGUE_USE 6) ; As USE insns are not meaningful after reload,
                        ; this unspec is used to prevent the deletion of
                        ; and stack frame generation.  Operand 0 is the
                        ; register to "use".
    (UNSPEC_CHECK_ARCH 7); Set CCs to indicate 26-bit or 32-bit mode.
+   (UNSPEC_WSHUFH    8) ; Used by the intrinsic form of the iWMMXt WSHUFH instruction.
+   (UNSPEC_WACC      9) ; Used by the intrinsic form of the iWMMXt WACC instruction.
+   (UNSPEC_TMOVMSK  10) ; Used by the intrinsic form of the iWMMXt TMOVMSK instruction.
+   (UNSPEC_WSAD     11) ; Used by the intrinsic form of the iWMMXt WSAD instruction.
+   (UNSPEC_WSADZ    12) ; Used by the intrinsic form of the iWMMXt WSADZ instruction.
+   (UNSPEC_WMACS    13) ; Used by the intrinsic form of the iWMMXt WMACS instruction.
+   (UNSPEC_WMACU    14) ; Used by the intrinsic form of the iWMMXt WMACU instruction.
+   (UNSPEC_WMACSZ   15) ; Used by the intrinsic form of the iWMMXt WMACSZ instruction.
+   (UNSPEC_WMACUZ   16) ; Used by the intrinsic form of the iWMMXt WMACUZ instruction.
+   (UNSPEC_CLRDI    17) ; Used by the intrinsic form of the iWMMXt CLRDI instruction.
+   (UNSPEC_WMADDS   18) ; Used by the intrinsic form of the iWMMXt WMADDS instruction.
+   (UNSPEC_WMADDU   19) ; Used by the intrinsic form of the iWMMXt WMADDU instruction.
   ]
 )
 
                        ;   a 32-bit object.
    (VUNSPEC_POOL_8   7) ; `pool-entry(8)'.  An entry in the constant pool for
                        ;   a 64-bit object.
+   (VUNSPEC_TMRC     8) ; Used by the iWMMXt TMRC instruction.
+   (VUNSPEC_TMCR     9) ; Used by the iWMMXt TMCR instruction.
+   (VUNSPEC_ALIGN8   10) ; 8-byte alignment version of VUNSPEC_ALIGN
+   (VUNSPEC_WCMP_EQ  11) ; Used by the iWMMXt WCMPEQ instructions
+   (VUNSPEC_WCMP_GTU 12) ; Used by the iWMMXt WCMPGTU instructions
+   (VUNSPEC_WCMP_GT  13) ; Used by the iwMMXT WCMPGT instructions
+   (VUNSPEC_EH_RETURN 20); Use to override the return address for exception
+                        ; handling.
   ]
 )
 \f
 ; patterns that share the same RTL in both ARM and Thumb code.
 (define_attr "is_thumb" "no,yes" (const (symbol_ref "thumb_code")))
 
-; PROG_MODE attribute is used to determine whether condition codes are
-; clobbered by a call insn: they are if in prog32 mode.  This is controlled
-; by the -mapcs-{32,26} flag, and possibly the -mcpu=... option.
-(define_attr "prog_mode" "prog26,prog32" (const (symbol_ref "arm_prog_mode")))
-
 ; IS_STRONGARM is set to 'yes' when compiling for StrongARM, it affects
 ; scheduling decisions for the load unit and the multiplier.
-(define_attr "is_strongarm" "no,yes" (const (symbol_ref "arm_is_strong")))
+(define_attr "is_strongarm" "no,yes" (const (symbol_ref "arm_tune_strongarm")))
+
+; IS_XSCALE is set to 'yes' when compiling for XScale.
+(define_attr "is_xscale" "no,yes" (const (symbol_ref "arm_tune_xscale")))
 
 ;; Operand number of an input operand that is shifted.  Zero if the
 ;; given instruction does not shift one of its input operands.
-(define_attr "is_xscale" "no,yes" (const (symbol_ref "arm_is_xscale")))
 (define_attr "shift" "" (const_int 0))
 
 ; Floating Point Unit.  If we only have floating point emulation, then there
 ; is no point in scheduling the floating point insns.  (Well, for best
 ; performance we should try and group them together).
-(define_attr "fpu" "fpa,fpe2,fpe3" (const (symbol_ref "arm_fpu_attr")))
+(define_attr "fpu" "none,fpa,fpe2,fpe3,maverick,vfp"
+  (const (symbol_ref "arm_fpu_attr")))
 
 ; LENGTH of an instruction (in bytes)
 (define_attr "length" "" (const_int 4))
   (set_attr "length" "4")
   (set_attr "pool_range" "250")])
 
+;; The instruction used to implement a particular pattern.  This
+;; information is used by pipeline descriptions to provide accurate
+;; scheduling information.
+
+(define_attr "insn"
+        "smulxy,smlaxy,smlalxy,smulwy,smlawx,mul,muls,mla,mlas,umull,umulls,umlal,umlals,smull,smulls,smlal,smlals,smlawy,smuad,smuadx,smlad,smladx,smusd,smusdx,smlsd,smlsdx,smmul,smmulr,other"
+        (const_string "other"))
+
 ; TYPE attribute is used to detect floating point instructions which, if
 ; running on a co-processor can run in parallel with other, basic instructions
 ; If write-buffer scheduling is enabled then it can also be used in the
 ; scheduling of writes.
 
 ; Classification of each insn
-; normal       any data instruction that doesn't hit memory or fp regs
+; alu          any alu  instruction that doesn't hit memory or fp
+;              regs or have a shifted source operand
+; alu_shift    any data instruction that doesn't hit memory or fp
+;              regs, but has a source operand shifted by a constant
+; alu_shift_reg        any data instruction that doesn't hit memory or fp
+;              regs, but has a source operand shifted by a register value
 ; mult         a multiply instruction
 ; block                blockage insn, this blocks all functional units
 ; float                a floating point arithmetic operation (subject to expansion)
 ;              even on a machine with an fpa.
 ; f_load       a floating point load from memory
 ; f_store      a floating point store to memory
+; f_load[sd]   single/double load from memory
+; f_store[sd]  single/double store to memory
+; f_flag       a transfer of co-processor flags to the CPSR
 ; f_mem_r      a transfer of a floating point register to a real reg via mem
 ; r_mem_f      the reverse of f_mem_r
 ; f_2_r                fast transfer float to arm (no memory needed)
 ; r_2_f                fast transfer arm to float
+; f_cvt                convert floating<->integral
+; branch       a branch
 ; call         a subroutine call
-; load         any load from memory
-; store1       store 1 word to memory from arm registers
+; load_byte    load byte(s) from memory to arm registers
+; load1                load 1 word from memory to arm registers
+; load2         load 2 words from memory to arm registers
+; load3         load 3 words from memory to arm registers
+; load4         load 4 words from memory to arm registers
+; store                store 1 word to memory from arm registers
 ; store2       store 2 words
 ; store3       store 3 words
-; store4       store 4 words
+; store4       store 4 (or more) words
+;  Additions for Cirrus Maverick co-processor:
+; mav_farith   Floating point arithmetic (4 cycle)
+; mav_dmult    Double multiplies (7 cycle)
 ;
 (define_attr "type"
-       "normal,mult,block,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith,float_em,f_load,f_store,f_mem_r,r_mem_f,f_2_r,r_2_f,call,load,store1,store2,store3,store4" 
-       (const_string "normal"))
+       "alu,alu_shift,alu_shift_reg,mult,block,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith,f_flag,float_em,f_load,f_store,f_loads,f_loadd,f_stores,f_stored,f_mem_r,r_mem_f,f_2_r,r_2_f,f_cvt,branch,call,load_byte,load1,load2,load3,load4,store1,store2,store3,store4,mav_farith,mav_dmult" 
+       (if_then_else 
+        (eq_attr "insn" "smulxy,smlaxy,smlalxy,smulwy,smlawx,mul,muls,mla,mlas,umull,umulls,umlal,umlals,smull,smulls,smlal,smlals")
+        (const_string "mult")
+        (const_string "alu")))
 
 ; Load scheduling, set from the arm_ld_sched variable
 ; initialized by arm_override_options() 
 
 (define_attr "conds" "use,set,clob,jump_clob,nocond"
        (if_then_else (eq_attr "type" "call")
-        (if_then_else (eq_attr "prog_mode" "prog32")
-         (const_string "clob") (const_string "nocond"))
+        (const_string "clob")
         (const_string "nocond")))
 
 ; Predicable means that the insn can be conditionally executed based on
 
 ; Only model the write buffer for ARM6 and ARM7.  Earlier processors don't
 ; have one.  Later ones, such as StrongARM, have write-back caches, so don't
-; suffer blockages enough to warrent modelling this (and it can adversely
+; suffer blockages enough to warrant modelling this (and it can adversely
 ; affect the schedule).
-(define_attr "model_wbuf" "no,yes" (const (symbol_ref "arm_is_6_or_7")))
+(define_attr "model_wbuf" "no,yes" (const (symbol_ref "arm_tune_wbuf")))
 
 ; WRITE_CONFLICT implies that a read following an unrelated write is likely
 ; to stall the processor.  Used with model_wbuf above.
 (define_attr "write_conflict" "no,yes"
   (if_then_else (eq_attr "type"
-                "block,float_em,f_load,f_store,f_mem_r,r_mem_f,call,load")
+                "block,float_em,f_load,f_store,f_mem_r,r_mem_f,call,load1")
                (const_string "yes")
                (const_string "no")))
 
 ; than one on the main cpu execution unit.
 (define_attr "core_cycles" "single,multi"
   (if_then_else (eq_attr "type"
-                "normal,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith")
+                "alu,alu_shift,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith")
                (const_string "single")
                (const_string "multi")))
 
 ;; distant label.  Only applicable to Thumb code.
 (define_attr "far_jump" "yes,no" (const_string "no"))
 
-;; (define_function_unit {name} {num-units} {n-users} {test}
-;;                       {ready-delay} {issue-delay} [{conflict-list}])
-
-;;--------------------------------------------------------------------
-;; Floating point unit (FPA)
-;;--------------------------------------------------------------------
-(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa")
-                                    (eq_attr "type" "fdivx")) 71 69)
 
-(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa")
-                                    (eq_attr "type" "fdivd")) 59 57)
+;;---------------------------------------------------------------------------
+;; Mode macros
 
-(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa")
-                                    (eq_attr "type" "fdivs")) 31 29)
+; A list of modes that are exactly 64 bits in size.  We use this to expand
+; some splits that are the same for all modes when operating on ARM 
+; registers.
+(define_mode_macro ANY64 [DI DF V8QI V4HI V2SI V2SF])
 
-(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa")
-                                    (eq_attr "type" "fmul")) 9 7)
+;;---------------------------------------------------------------------------
+;; Predicates
 
-(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa")
-                                    (eq_attr "type" "ffmul")) 6 4)
+(include "predicates.md")
 
-(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa")
-                                    (eq_attr "type" "farith")) 4 2)
+;;---------------------------------------------------------------------------
+;; Pipeline descriptions
 
-(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa")
-                                    (eq_attr "type" "ffarith")) 2 2)
+;; Processor type.  This is created automatically from arm-cores.def.
+(include "arm-tune.md")
 
-(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa")
-                                    (eq_attr "type" "r_2_f")) 5 3)
+;; True if the generic scheduling description should be used.
 
-(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa")
-                                    (eq_attr "type" "f_2_r")) 1 2)
+(define_attr "generic_sched" "yes,no"
+  (const (if_then_else 
+          (eq_attr "tune" "arm926ejs,arm1020e,arm1026ejs,arm1136js,arm1136jfs") 
+          (const_string "no")
+          (const_string "yes"))))
 
-; The fpa10 doesn't really have a memory read unit, but it can start to
-; speculatively execute the instruction in the pipeline, provided the data
-; is already loaded, so pretend reads have a delay of 2 (and that the
-; pipeline is infinite).
+(define_attr "generic_vfp" "yes,no"
+  (const (if_then_else
+         (and (eq_attr "fpu" "vfp")
+              (eq_attr "tune" "!arm1020e,arm1022e"))
+         (const_string "yes")
+         (const_string "no"))))
 
-(define_function_unit "fpa_mem" 1 0 (and (eq_attr "fpu" "fpa")
-                                        (eq_attr "type" "f_load")) 3 1)
+(include "arm-generic.md")
+(include "arm926ejs.md")
+(include "arm1020e.md")
+(include "arm1026ejs.md")
+(include "arm1136jfs.md")
 
-;;--------------------------------------------------------------------
-;; Write buffer
-;;--------------------------------------------------------------------
-; Strictly, we should model a 4-deep write buffer for ARM7xx based chips
-;
-; The write buffer on some of the arm6 processors is hard to model exactly.
-; There is room in the buffer for up to two addresses and up to eight words
-; of memory, but the two needn't be split evenly.  When writing the two
-; addresses are fully pipelined.  However, a read from memory that is not
-; currently in the cache will block until the writes have completed.
-; It is normally the case that FCLK and MCLK will be in the ratio 2:1, so
-; writes will take 2 FCLK cycles per word, if FCLK and MCLK are asynchronous
-; (they aren't allowed to be at present) then there is a startup cost of 1MCLK
-; cycle to add as well.
-
-(define_function_unit "write_buf" 1 2
-  (and (eq_attr "model_wbuf" "yes")
-       (eq_attr "type" "store1,r_mem_f")) 5 3)
-(define_function_unit "write_buf" 1 2 
-  (and (eq_attr "model_wbuf" "yes")
-       (eq_attr "type" "store2")) 7 4)
-(define_function_unit "write_buf" 1 2
-  (and (eq_attr "model_wbuf" "yes")
-       (eq_attr "type" "store3")) 9 5)
-(define_function_unit "write_buf" 1 2
-  (and (eq_attr "model_wbuf" "yes")
-       (eq_attr "type" "store4")) 11 6)
-
-;;--------------------------------------------------------------------
-;; Write blockage unit
-;;--------------------------------------------------------------------
-; The write_blockage unit models (partially), the fact that reads will stall
-; until the write buffer empties.
-; The f_mem_r and r_mem_f could also block, but they are to the stack,
-; so we don't model them here
-(define_function_unit "write_blockage" 1 0 (and (eq_attr "model_wbuf" "yes")
-                                               (eq_attr "type" "store1")) 5 5
-       [(eq_attr "write_conflict" "yes")])
-(define_function_unit "write_blockage" 1 0 (and (eq_attr "model_wbuf" "yes")
-                                               (eq_attr "type" "store2")) 7 7
-       [(eq_attr "write_conflict" "yes")])
-(define_function_unit "write_blockage" 1 0 (and (eq_attr "model_wbuf" "yes")
-                                               (eq_attr "type" "store3")) 9 9
-       [(eq_attr "write_conflict" "yes")])
-(define_function_unit "write_blockage" 1 0
-       (and (eq_attr "model_wbuf" "yes") (eq_attr "type" "store4")) 11 11
-       [(eq_attr "write_conflict" "yes")])
-(define_function_unit "write_blockage" 1 0
-       (and (eq_attr "model_wbuf" "yes")
-            (eq_attr "write_conflict" "yes")) 1 1)
-
-;;--------------------------------------------------------------------
-;; Core unit
-;;--------------------------------------------------------------------
-; Everything must spend at least one cycle in the core unit
-(define_function_unit "core" 1 0 (eq_attr "core_cycles" "single") 1 1)
-
-(define_function_unit "core" 1 0
-  (and (eq_attr "ldsched" "yes") (eq_attr "type" "store1")) 1 1)
-
-(define_function_unit "core" 1 0
-  (and (eq_attr "ldsched" "yes") (eq_attr "type" "load")) 2 1)
-
-;; We do not need to conditionalize the define_function_unit immediately
-;; above.  This one will be ignored for anything other than xscale
-;; compiles and for xscale compiles it provides a larger delay
-;; and the scheduler will DTRT.
-;; FIXME: this test needs to be revamped to not depend on this feature 
-;; of the scheduler.
-
-(define_function_unit "core" 1 0
-  (and (and (eq_attr "ldsched" "yes") (eq_attr "type" "load"))
-       (eq_attr "is_xscale" "yes"))
-   3 1)
-
-(define_function_unit "core" 1 0
-  (and (eq_attr "ldsched" "!yes") (eq_attr "type" "load,store1")) 2 2)
-
-(define_function_unit "core" 1 0
-  (and (eq_attr "fpu" "fpa") (eq_attr "type" "f_load")) 3 3)
-
-(define_function_unit "core" 1 0
-  (and (eq_attr "fpu" "fpa") (eq_attr "type" "f_store")) 4 4)
-
-(define_function_unit "core" 1 0
-  (and (eq_attr "fpu" "fpa") (eq_attr "type" "r_mem_f")) 6 6)
-
-(define_function_unit "core" 1 0
-  (and (eq_attr "fpu" "fpa") (eq_attr "type" "f_mem_r")) 7 7)
-
-(define_function_unit "core" 1 0
-  (and (eq_attr "ldsched" "no") (eq_attr "type" "mult")) 16 16)
-
-(define_function_unit "core" 1 0
-  (and (and (eq_attr "ldsched" "yes") (eq_attr "is_strongarm" "no"))
-       (eq_attr "type" "mult")) 4 4)
-
-(define_function_unit "core" 1 0
-  (and (and (eq_attr "ldsched" "yes") (eq_attr "is_strongarm" "yes"))
-       (eq_attr "type" "mult")) 3 2)
-
-(define_function_unit "core" 1 0 (eq_attr "type" "store2") 3 3)
-
-(define_function_unit "core" 1 0 (eq_attr "type" "store3") 4 4)
-
-(define_function_unit "core" 1 0 (eq_attr "type" "store4") 5 5)
-
-(define_function_unit "core" 1 0
-  (and (eq_attr "core_cycles" "multi")
-       (eq_attr "type" "!mult,load,store1,store2,store3,store4")) 32 32)
 \f
-(include "cirrus.md")
-
 ;;---------------------------------------------------------------------------
 ;; Insn patterns
 ;;
     (clobber (reg:CC CC_REGNUM))])]
   "TARGET_EITHER"
   "
-  if (TARGET_CIRRUS)
+  if (TARGET_HARD_FLOAT && TARGET_MAVERICK)
     {
       if (!cirrus_fp_register (operands[0], DImode))
         operands[0] = force_reg (DImode, operands[0]);
        (plus:DI (match_operand:DI 1 "s_register_operand" "%0, 0")
                 (match_operand:DI 2 "s_register_operand" "r,  0")))
    (clobber (reg:CC CC_REGNUM))]
-  "TARGET_ARM && !TARGET_CIRRUS"
+  "TARGET_ARM && !(TARGET_HARD_FLOAT && TARGET_MAVERICK)"
   "#"
   "TARGET_ARM && reload_completed"
   [(parallel [(set (reg:CC_C CC_REGNUM)
                  (match_operand:SI 2 "s_register_operand" "r,r"))
                 (match_operand:DI 1 "s_register_operand" "r,0")))
    (clobber (reg:CC CC_REGNUM))]
-  "TARGET_ARM && !TARGET_CIRRUS"
+  "TARGET_ARM && !(TARGET_HARD_FLOAT && TARGET_MAVERICK)"
   "#"
   "TARGET_ARM && reload_completed"
   [(parallel [(set (reg:CC_C CC_REGNUM)
                  (match_operand:SI 2 "s_register_operand" "r,r"))
                 (match_operand:DI 1 "s_register_operand" "r,0")))
    (clobber (reg:CC CC_REGNUM))]
-  "TARGET_ARM && !TARGET_CIRRUS"
+  "TARGET_ARM && !(TARGET_HARD_FLOAT && TARGET_MAVERICK)"
   "#"
   "TARGET_ARM && reload_completed"
   [(parallel [(set (reg:CC_C CC_REGNUM)
   "
   if (TARGET_ARM && GET_CODE (operands[2]) == CONST_INT)
     {
-      arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0],
-                         operands[1],
-                         (no_new_pseudos ? 0 : preserve_subexpressions_p ()));
+      arm_split_constant (PLUS, SImode, NULL_RTX,
+                         INTVAL (operands[2]), operands[0], operands[1],
+                         optimize && !no_new_pseudos);
       DONE;
     }
   "
 )
 
-; If there is a scratch available, this will be faster than synthesising the
+; If there is a scratch available, this will be faster than synthesizing the
 ; addition.
 (define_peephole2
   [(match_scratch:SI 3 "r")
-   (set (match_operand:SI          0 "s_register_operand" "")
-       (plus:SI (match_operand:SI 1 "s_register_operand" "")
+   (set (match_operand:SI          0 "arm_general_register_operand" "")
+       (plus:SI (match_operand:SI 1 "arm_general_register_operand" "")
                 (match_operand:SI 2 "const_int_operand"  "")))]
   "TARGET_ARM &&
    !(const_ok_for_arm (INTVAL (operands[2]))
         || const_ok_for_arm (-INTVAL (operands[2])))"
   [(clobber (const_int 0))]
   "
-  arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0],
+  arm_split_constant (PLUS, SImode, curr_insn,
+                     INTVAL (operands[2]), operands[0],
                      operands[1], 0);
   DONE;
   "
 ;; Reloading and elimination of the frame pointer can
 ;; sometimes cause this optimization to be missed.
 (define_peephole2
-  [(set (match_operand:SI 0 "register_operand" "")
+  [(set (match_operand:SI 0 "arm_general_register_operand" "")
        (match_operand:SI 1 "const_int_operand" ""))
    (set (match_dup 0)
-       (plus:SI (match_dup 0) (match_operand:SI 2 "register_operand" "")))]
+       (plus:SI (match_dup 0) (reg:SI SP_REGNUM)))]
   "TARGET_THUMB
-   && REGNO (operands[2]) == STACK_POINTER_REGNUM 
    && (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) < 1024
    && (INTVAL (operands[1]) & 3) == 0"
-  [(set (match_dup 0) (plus:SI (match_dup 2) (match_dup 1)))]
+  [(set (match_dup 0) (plus:SI (reg:SI SP_REGNUM) (match_dup 1)))]
   ""
 )
 
   [(set_attr "conds" "set")]
 )
 
-;; These patterns are the same ones as the two regular addsi3_compare0
-;; patterns, except we write them slightly different - the combiner
-;; tends to generate them this way.
-(define_insn "*addsi3_compare0_for_combiner"
-  [(set (reg:CC CC_REGNUM)
-       (compare:CC
-        (match_operand:SI 1 "s_register_operand" "r,r")
-        (neg:SI (match_operand:SI 2 "arm_add_operand" "rI,L"))))
-   (set (match_operand:SI 0 "s_register_operand" "=r,r")
-       (plus:SI (match_dup 1) (match_dup 2)))]
+(define_insn "*compare_negsi_si"
+  [(set (reg:CC_Z CC_REGNUM)
+       (compare:CC_Z
+        (neg:SI (match_operand:SI 0 "s_register_operand" "r"))
+        (match_operand:SI 1 "s_register_operand" "r")))]
   "TARGET_ARM"
-  "@
-   add%?s\\t%0, %1, %2
-   sub%?s\\t%0, %1, #%n2"
+  "cmn%?\\t%1, %0"
   [(set_attr "conds" "set")]
 )
 
-(define_insn "*addsi3_compare0_scratch_for_combiner"
+;; This is the canonicalization of addsi3_compare0_for_combiner when the
+;; addend is a constant.
+(define_insn "*cmpsi2_addneg"
   [(set (reg:CC CC_REGNUM)
        (compare:CC
-        (match_operand:SI 0 "s_register_operand" "r,r")
-        (neg:SI (match_operand:SI 1 "arm_add_operand" "rI,L"))))]
-  "TARGET_ARM"
+        (match_operand:SI 1 "s_register_operand" "r,r")
+        (match_operand:SI 2 "arm_addimm_operand" "I,L")))
+   (set (match_operand:SI 0 "s_register_operand" "=r,r")
+       (plus:SI (match_dup 1)
+                (match_operand:SI 3 "arm_addimm_operand" "L,I")))]
+  "TARGET_ARM && INTVAL (operands[2]) == -INTVAL (operands[3])"
   "@
-   cmn%?\\t%0, %1
-   cmp%?\\t%0, #%n1"
+   sub%?s\\t%0, %1, %2
+   add%?s\\t%0, %1, #%n2"
   [(set_attr "conds" "set")]
 )
 
+;; Convert the sequence
+;;  sub  rd, rn, #1
+;;  cmn  rd, #1        (equivalent to cmp rd, #-1)
+;;  bne  dest
+;; into
+;;  subs rd, rn, #1
+;;  bcs  dest  ((unsigned)rn >= 1)
+;; similarly for the beq variant using bcc.
+;; This is a common looping idiom (while (n--))
+(define_peephole2
+  [(set (match_operand:SI 0 "arm_general_register_operand" "")
+       (plus:SI (match_operand:SI 1 "arm_general_register_operand" "")
+                (const_int -1)))
+   (set (match_operand 2 "cc_register" "")
+       (compare (match_dup 0) (const_int -1)))
+   (set (pc)
+       (if_then_else (match_operator 3 "equality_operator"
+                      [(match_dup 2) (const_int 0)])
+                     (match_operand 4 "" "")
+                     (match_operand 5 "" "")))]
+  "TARGET_ARM && peep2_reg_dead_p (3, operands[2])"
+  [(parallel[
+    (set (match_dup 2)
+        (compare:CC
+         (match_dup 1) (const_int 1)))
+    (set (match_dup 0) (plus:SI (match_dup 1) (const_int -1)))])
+   (set (pc)
+       (if_then_else (match_op_dup 3 [(match_dup 2) (const_int 0)])
+                     (match_dup 4)
+                     (match_dup 5)))]
+  "operands[2] = gen_rtx_REG (CCmode, CC_REGNUM);
+   operands[3] = gen_rtx_fmt_ee ((GET_CODE (operands[3]) == NE
+                                 ? GEU : LTU),
+                                VOIDmode, 
+                                operands[2], const0_rtx);"
+)
+
 ;; The next four insns work because they compare the result with one of
 ;; the operands, and we know that the use of the condition code is
 ;; either GEU or LTU, so we can use the carry flag from the addition
 )
 
 (define_insn "*addsi3_carryin_shift"
-  [(set (match_operand:SI 0 "s_register_operand" "")
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
        (plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))
                 (plus:SI
                   (match_operator:SI 2 "shift_operator"
-                     [(match_operand:SI 3 "s_register_operand" "")
-                      (match_operand:SI 4 "reg_or_int_operand" "")])
-                   (match_operand:SI 1 "s_register_operand" ""))))]
+                     [(match_operand:SI 3 "s_register_operand" "r")
+                      (match_operand:SI 4 "reg_or_int_operand" "rM")])
+                   (match_operand:SI 1 "s_register_operand" "r"))))]
   "TARGET_ARM"
   "adc%?\\t%0, %1, %3%S2"
-  [(set_attr "conds" "use")]
+  [(set_attr "conds" "use")
+   (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "")
+                     (const_string "alu_shift")
+                     (const_string "alu_shift_reg")))]
 )
 
 (define_insn "*addsi3_carryin_alt1"
    (set_attr "length" "4,8")]
 )
 
-(define_insn "*arm_addsf3"
-  [(set (match_operand:SF          0 "s_register_operand" "=f,f")
-       (plus:SF (match_operand:SF 1 "s_register_operand" "%f,f")
-                (match_operand:SF 2 "fpu_add_operand"    "fG,H")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "@
-   adf%?s\\t%0, %1, %2
-   suf%?s\\t%0, %1, #%N2"
-  [(set_attr "type" "farith")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*arm_adddf3"
-  [(set (match_operand:DF          0 "s_register_operand" "=f,f")
-       (plus:DF (match_operand:DF 1 "s_register_operand" "%f,f")
-                (match_operand:DF 2 "fpu_add_operand"    "fG,H")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "@
-   adf%?d\\t%0, %1, %2
-   suf%?d\\t%0, %1, #%N2"
-  [(set_attr "type" "farith")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*adddf_esfdf_df"
-  [(set (match_operand:DF           0 "s_register_operand" "=f,f")
-       (plus:DF (float_extend:DF
-                 (match_operand:SF 1 "s_register_operand"  "f,f"))
-                (match_operand:DF  2 "fpu_add_operand"    "fG,H")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "@
-   adf%?d\\t%0, %1, %2
-   suf%?d\\t%0, %1, #%N2"
-  [(set_attr "type" "farith")
-   (set_attr "predicable" "yes")]
-)
+; transform ((x << y) - 1) to ~(~(x-1) << y)  Where X is a constant.
+(define_split
+  [(set (match_operand:SI 0 "s_register_operand" "")
+       (plus:SI (ashift:SI (match_operand:SI 1 "const_int_operand" "")
+                           (match_operand:SI 2 "s_register_operand" ""))
+                (const_int -1)))
+   (clobber (match_operand:SI 3 "s_register_operand" ""))]
+  "TARGET_ARM"
+  [(set (match_dup 3) (match_dup 1))
+   (set (match_dup 0) (not:SI (ashift:SI (match_dup 3) (match_dup 2))))]
+  "
+  operands[1] = GEN_INT (~(INTVAL (operands[1]) - 1));
+")
 
-(define_insn "*adddf_df_esfdf"
-  [(set (match_operand:DF           0 "s_register_operand" "=f")
-       (plus:DF (match_operand:DF  1 "s_register_operand"  "f")
-                (float_extend:DF
-                 (match_operand:SF 2 "s_register_operand"  "f"))))]
+(define_expand "addsf3"
+  [(set (match_operand:SF          0 "s_register_operand" "")
+       (plus:SF (match_operand:SF 1 "s_register_operand" "")
+                (match_operand:SF 2 "arm_float_add_operand" "")))]
   "TARGET_ARM && TARGET_HARD_FLOAT"
-  "adf%?d\\t%0, %1, %2"
-  [(set_attr "type" "farith")
-   (set_attr "predicable" "yes")]
-)
+  "
+  if (TARGET_MAVERICK
+      && !cirrus_fp_register (operands[2], SFmode))
+    operands[2] = force_reg (SFmode, operands[2]);
+")
 
-(define_insn "*adddf_esfdf_esfdf"
-  [(set (match_operand:DF           0 "s_register_operand" "=f")
-       (plus:DF (float_extend:DF 
-                 (match_operand:SF 1 "s_register_operand" "f"))
-                (float_extend:DF
-                 (match_operand:SF 2 "s_register_operand" "f"))))]
+(define_expand "adddf3"
+  [(set (match_operand:DF          0 "s_register_operand" "")
+       (plus:DF (match_operand:DF 1 "s_register_operand" "")
+                (match_operand:DF 2 "arm_float_add_operand" "")))]
   "TARGET_ARM && TARGET_HARD_FLOAT"
-  "adf%?d\\t%0, %1, %2"
-  [(set_attr "type" "farith")
-   (set_attr "predicable" "yes")]
-)
+  "
+  if (TARGET_MAVERICK
+      && !cirrus_fp_register (operands[2], DFmode))
+    operands[2] = force_reg (DFmode, operands[2]);
+")
 
 (define_expand "subdi3"
  [(parallel
     (clobber (reg:CC CC_REGNUM))])]
   "TARGET_EITHER"
   "
-  if (TARGET_CIRRUS
+  if (TARGET_HARD_FLOAT && TARGET_MAVERICK
       && TARGET_ARM
       && cirrus_fp_register (operands[0], DImode)
       && cirrus_fp_register (operands[1], DImode))
     {
       if (TARGET_ARM)
         {
-          arm_split_constant (MINUS, SImode, INTVAL (operands[1]), operands[0],
-                             operands[2],
-                             (no_new_pseudos ? 0
-                              :  preserve_subexpressions_p ()));
+          arm_split_constant (MINUS, SImode, NULL_RTX,
+                             INTVAL (operands[1]), operands[0],
+                             operands[2], optimize && !no_new_pseudos);
           DONE;
        }
       else /* TARGET_THUMB */
    && !const_ok_for_arm (INTVAL (operands[1]))"
   [(clobber (const_int 0))]
   "
-  arm_split_constant (MINUS, SImode, INTVAL (operands[1]), operands[0],
-                     operands[2], 0);
+  arm_split_constant (MINUS, SImode, curr_insn,
+                      INTVAL (operands[1]), operands[0], operands[2], 0);
   DONE;
   "
   [(set_attr "length" "4,16")
 
 (define_peephole2
   [(match_scratch:SI 3 "r")
-   (set (match_operand:SI           0 "s_register_operand" "")
+   (set (match_operand:SI 0 "arm_general_register_operand" "")
        (minus:SI (match_operand:SI 1 "const_int_operand" "")
-                 (match_operand:SI 2 "s_register_operand" "")))]
+                 (match_operand:SI 2 "arm_general_register_operand" "")))]
   "TARGET_ARM
    && !const_ok_for_arm (INTVAL (operands[1]))
    && const_ok_for_arm (~INTVAL (operands[1]))"
    (set_attr "length" "*,8")]
 )
 
-(define_insn "*arm_subsf3"
-  [(set (match_operand:SF 0 "s_register_operand" "=f,f")
-       (minus:SF (match_operand:SF 1 "fpu_rhs_operand" "f,G")
-                 (match_operand:SF 2 "fpu_rhs_operand" "fG,f")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "@
-   suf%?s\\t%0, %1, %2
-   rsf%?s\\t%0, %2, %1"
-  [(set_attr "type" "farith")]
-)
-
-(define_insn "*arm_subdf3"
-  [(set (match_operand:DF           0 "s_register_operand" "=f,f")
-       (minus:DF (match_operand:DF 1 "fpu_rhs_operand"     "f,G")
-                 (match_operand:DF 2 "fpu_rhs_operand"    "fG,f")))]
+(define_expand "subsf3"
+  [(set (match_operand:SF           0 "s_register_operand" "")
+       (minus:SF (match_operand:SF 1 "arm_float_rhs_operand" "")
+                 (match_operand:SF 2 "arm_float_rhs_operand" "")))]
   "TARGET_ARM && TARGET_HARD_FLOAT"
-  "@
-   suf%?d\\t%0, %1, %2
-   rsf%?d\\t%0, %2, %1"
-  [(set_attr "type" "farith")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*subdf_esfdf_df"
-  [(set (match_operand:DF            0 "s_register_operand" "=f")
-       (minus:DF (float_extend:DF
-                  (match_operand:SF 1 "s_register_operand"  "f"))
-                 (match_operand:DF  2 "fpu_rhs_operand"    "fG")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "suf%?d\\t%0, %1, %2"
-  [(set_attr "type" "farith")
-   (set_attr "predicable" "yes")]
-)
+  "
+  if (TARGET_MAVERICK)
+    {
+      if (!cirrus_fp_register (operands[1], SFmode))
+        operands[1] = force_reg (SFmode, operands[1]);
+      if (!cirrus_fp_register (operands[2], SFmode))
+        operands[2] = force_reg (SFmode, operands[2]);
+    }
+")
 
-(define_insn "*subdf_df_esfdf"
-  [(set (match_operand:DF 0 "s_register_operand" "=f,f")
-       (minus:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G")
-                 (float_extend:DF
-                  (match_operand:SF 2 "s_register_operand" "f,f"))))]
+(define_expand "subdf3"
+  [(set (match_operand:DF           0 "s_register_operand" "")
+       (minus:DF (match_operand:DF 1 "arm_float_rhs_operand" "")
+                 (match_operand:DF 2 "arm_float_rhs_operand" "")))]
   "TARGET_ARM && TARGET_HARD_FLOAT"
-  "@
-   suf%?d\\t%0, %1, %2
-   rsf%?d\\t%0, %2, %1"
-  [(set_attr "type" "farith")
-   (set_attr "predicable" "yes")]
-)
+  "
+  if (TARGET_MAVERICK)
+    {
+       if (!cirrus_fp_register (operands[1], DFmode))
+         operands[1] = force_reg (DFmode, operands[1]);
+       if (!cirrus_fp_register (operands[2], DFmode))
+         operands[2] = force_reg (DFmode, operands[2]);
+    }
+")
 
-(define_insn "*subdf_esfdf_esfdf"
-  [(set (match_operand:DF 0 "s_register_operand" "=f")
-       (minus:DF (float_extend:DF
-                  (match_operand:SF 1 "s_register_operand" "f"))
-                 (float_extend:DF
-                  (match_operand:SF 2 "s_register_operand" "f"))))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "suf%?d\\t%0, %1, %2"
-  [(set_attr "type" "farith")
-   (set_attr "predicable" "yes")]
-)
 \f
 ;; Multiplication insns
 
                 (match_operand:SI 1 "s_register_operand" "%?r,0")))]
   "TARGET_ARM"
   "mul%?\\t%0, %2, %1"
-  [(set_attr "type" "mult")
+  [(set_attr "insn" "mul")
    (set_attr "predicable" "yes")]
 )
 
   "TARGET_THUMB"
   "*
   if (which_alternative < 2)
-    return \"mov\\t%0, %1\;mul\\t%0, %0, %2\";
+    return \"mov\\t%0, %1\;mul\\t%0, %2\";
   else
-    return \"mul\\t%0, %0, %2\";
+    return \"mul\\t%0, %2\";
   "
   [(set_attr "length" "4,4,2")
-   (set_attr "type" "mult")]
+   (set_attr "insn" "mul")]
 )
 
 (define_insn "*mulsi3_compare0"
                         (const_int 0)))
    (set (match_operand:SI 0 "s_register_operand" "=&r,&r")
        (mult:SI (match_dup 2) (match_dup 1)))]
-  "TARGET_ARM && !arm_is_xscale"
+  "TARGET_ARM"
   "mul%?s\\t%0, %2, %1"
   [(set_attr "conds" "set")
-   (set_attr "type" "mult")]
+   (set_attr "insn" "muls")]
 )
 
 (define_insn "*mulsi_compare0_scratch"
                          (match_operand:SI 1 "s_register_operand" "%?r,0"))
                         (const_int 0)))
    (clobber (match_scratch:SI 0 "=&r,&r"))]
-  "TARGET_ARM && !arm_is_xscale"
+  "TARGET_ARM"
   "mul%?s\\t%0, %2, %1"
   [(set_attr "conds" "set")
-   (set_attr "type" "mult")]
+   (set_attr "insn" "muls")]
 )
 
 ;; Unnamed templates to match MLA instruction.
          (match_operand:SI 3 "s_register_operand" "?r,r,0,0")))]
   "TARGET_ARM"
   "mla%?\\t%0, %2, %1, %3"
-  [(set_attr "type" "mult")
+  [(set_attr "insn" "mla")
    (set_attr "predicable" "yes")]
 )
 
    (set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r,&r")
        (plus:SI (mult:SI (match_dup 2) (match_dup 1))
                 (match_dup 3)))]
-  "TARGET_ARM && !arm_is_xscale"
+  "TARGET_ARM"
   "mla%?s\\t%0, %2, %1, %3"
   [(set_attr "conds" "set")
-   (set_attr "type" "mult")]
+   (set_attr "insn" "mlas")]
 )
 
 (define_insn "*mulsi3addsi_compare0_scratch"
                  (match_operand:SI 3 "s_register_operand" "?r,r,0,0"))
         (const_int 0)))
    (clobber (match_scratch:SI 0 "=&r,&r,&r,&r"))]
-  "TARGET_ARM && !arm_is_xscale"
+  "TARGET_ARM"
   "mla%?s\\t%0, %2, %1, %3"
   [(set_attr "conds" "set")
-   (set_attr "type" "mult")]
+   (set_attr "insn" "mlas")]
 )
 
-;; Unnamed template to match long long multiply-accumlate (smlal)
+;; Unnamed template to match long long multiply-accumulate (smlal)
 
 (define_insn "*mulsidi3adddi"
   [(set (match_operand:DI 0 "s_register_operand" "=&r")
          (sign_extend:DI (match_operand:SI 2 "s_register_operand" "%r"))
          (sign_extend:DI (match_operand:SI 3 "s_register_operand" "r")))
         (match_operand:DI 1 "s_register_operand" "0")))]
-  "TARGET_ARM && arm_fast_multiply"
+  "TARGET_ARM && arm_arch3m"
   "smlal%?\\t%Q0, %R0, %3, %2"
-  [(set_attr "type" "mult")
+  [(set_attr "insn" "smlal")
    (set_attr "predicable" "yes")]
 )
 
        (mult:DI
         (sign_extend:DI (match_operand:SI 1 "s_register_operand" "%r"))
         (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r"))))]
-  "TARGET_ARM && arm_fast_multiply"
+  "TARGET_ARM && arm_arch3m"
   "smull%?\\t%Q0, %R0, %1, %2"
-  [(set_attr "type" "mult")
+  [(set_attr "insn" "smull")
    (set_attr "predicable" "yes")]
 )
 
        (mult:DI
         (zero_extend:DI (match_operand:SI 1 "s_register_operand" "%r"))
         (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r"))))]
-  "TARGET_ARM && arm_fast_multiply"
+  "TARGET_ARM && arm_arch3m"
   "umull%?\\t%Q0, %R0, %1, %2"
-  [(set_attr "type" "mult")
+  [(set_attr "insn" "umull")
    (set_attr "predicable" "yes")]
 )
 
-;; Unnamed template to match long long unsigned multiply-accumlate (umlal)
+;; Unnamed template to match long long unsigned multiply-accumulate (umlal)
 
 (define_insn "*umulsidi3adddi"
   [(set (match_operand:DI 0 "s_register_operand" "=&r")
          (zero_extend:DI (match_operand:SI 2 "s_register_operand" "%r"))
          (zero_extend:DI (match_operand:SI 3 "s_register_operand" "r")))
         (match_operand:DI 1 "s_register_operand" "0")))]
-  "TARGET_ARM && arm_fast_multiply"
+  "TARGET_ARM && arm_arch3m"
   "umlal%?\\t%Q0, %R0, %3, %2"
-  [(set_attr "type" "mult")
+  [(set_attr "insn" "umlal")
    (set_attr "predicable" "yes")]
 )
 
           (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")))
          (const_int 32))))
    (clobber (match_scratch:SI 3 "=&r,&r"))]
-  "TARGET_ARM && arm_fast_multiply"
+  "TARGET_ARM && arm_arch3m"
   "smull%?\\t%3, %0, %2, %1"
-  [(set_attr "type" "mult")
+  [(set_attr "insn" "smull")
    (set_attr "predicable" "yes")]
 )
 
           (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")))
          (const_int 32))))
    (clobber (match_scratch:SI 3 "=&r,&r"))]
-  "TARGET_ARM && arm_fast_multiply"
+  "TARGET_ARM && arm_arch3m"
   "umull%?\\t%3, %0, %2, %1"
-  [(set_attr "type" "mult")
+  [(set_attr "insn" "umull")
    (set_attr "predicable" "yes")]
 )
 
                  (match_operand:HI 1 "s_register_operand" "%r"))
                 (sign_extend:SI
                  (match_operand:HI 2 "s_register_operand" "r"))))]
-  "TARGET_ARM && arm_is_xscale"
+  "TARGET_ARM && arm_arch5e"
   "smulbb%?\\t%0, %1, %2"
-  [(set_attr "type" "mult")]
+  [(set_attr "insn" "smulxy")
+   (set_attr "predicable" "yes")]
+)
+
+(define_insn "*mulhisi3tb"
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
+       (mult:SI (ashiftrt:SI
+                 (match_operand:SI 1 "s_register_operand" "r")
+                 (const_int 16))
+                (sign_extend:SI
+                 (match_operand:HI 2 "s_register_operand" "r"))))]
+  "TARGET_ARM && arm_arch5e"
+  "smultb%?\\t%0, %1, %2"
+  [(set_attr "insn" "smulxy")
+   (set_attr "predicable" "yes")]
+)
+
+(define_insn "*mulhisi3bt"
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
+       (mult:SI (sign_extend:SI
+                 (match_operand:HI 1 "s_register_operand" "r"))
+                (ashiftrt:SI
+                 (match_operand:SI 2 "s_register_operand" "r")
+                 (const_int 16))))]
+  "TARGET_ARM && arm_arch5e"
+  "smulbt%?\\t%0, %1, %2"
+  [(set_attr "insn" "smulxy")
+   (set_attr "predicable" "yes")]
+)
+
+(define_insn "*mulhisi3tt"
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
+       (mult:SI (ashiftrt:SI
+                 (match_operand:SI 1 "s_register_operand" "r")
+                 (const_int 16))
+                (ashiftrt:SI
+                 (match_operand:SI 2 "s_register_operand" "r")
+                 (const_int 16))))]
+  "TARGET_ARM && arm_arch5e"
+  "smultt%?\\t%0, %1, %2"
+  [(set_attr "insn" "smulxy")
+   (set_attr "predicable" "yes")]
 )
 
 (define_insn "*mulhisi3addsi"
                           (match_operand:HI 2 "s_register_operand" "%r"))
                          (sign_extend:SI
                           (match_operand:HI 3 "s_register_operand" "r")))))]
-  "TARGET_ARM && arm_is_xscale"
+  "TARGET_ARM && arm_arch5e"
   "smlabb%?\\t%0, %2, %3, %1"
-  [(set_attr "type" "mult")]
+  [(set_attr "insn" "smlaxy")
+   (set_attr "predicable" "yes")]
 )
 
 (define_insn "*mulhidi3adddi"
                    (match_operand:HI 2 "s_register_operand" "%r"))
                   (sign_extend:DI
                    (match_operand:HI 3 "s_register_operand" "r")))))]
-  "TARGET_ARM && arm_is_xscale"
+  "TARGET_ARM && arm_arch5e"
   "smlalbb%?\\t%Q0, %R0, %2, %3"
-[(set_attr "type" "mult")])
-
-(define_insn "*arm_mulsf3"
-  [(set (match_operand:SF 0 "s_register_operand" "=f")
-       (mult:SF (match_operand:SF 1 "s_register_operand" "f")
-                (match_operand:SF 2 "fpu_rhs_operand" "fG")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "fml%?s\\t%0, %1, %2"
-  [(set_attr "type" "ffmul")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*arm_muldf3"
-  [(set (match_operand:DF 0 "s_register_operand" "=f")
-       (mult:DF (match_operand:DF 1 "s_register_operand" "f")
-                (match_operand:DF 2 "fpu_rhs_operand" "fG")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "muf%?d\\t%0, %1, %2"
-  [(set_attr "type" "fmul")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*muldf_esfdf_df"
-  [(set (match_operand:DF 0 "s_register_operand" "=f")
-       (mult:DF (float_extend:DF
-                 (match_operand:SF 1 "s_register_operand" "f"))
-                (match_operand:DF 2 "fpu_rhs_operand" "fG")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "muf%?d\\t%0, %1, %2"
-  [(set_attr "type" "fmul")
-   (set_attr "predicable" "yes")]
-)
+  [(set_attr "insn" "smlalxy")
+   (set_attr "predicable" "yes")])
 
-(define_insn "*muldf_df_esfdf"
-  [(set (match_operand:DF 0 "s_register_operand" "=f")
-       (mult:DF (match_operand:DF 1 "s_register_operand" "f")
-                (float_extend:DF
-                 (match_operand:SF 2 "s_register_operand" "f"))))]
+(define_expand "mulsf3"
+  [(set (match_operand:SF          0 "s_register_operand" "")
+       (mult:SF (match_operand:SF 1 "s_register_operand" "")
+                (match_operand:SF 2 "arm_float_rhs_operand" "")))]
   "TARGET_ARM && TARGET_HARD_FLOAT"
-  "muf%?d\\t%0, %1, %2"
-  [(set_attr "type" "fmul")
-   (set_attr "predicable" "yes")]
-)
+  "
+  if (TARGET_MAVERICK
+      && !cirrus_fp_register (operands[2], SFmode))
+    operands[2] = force_reg (SFmode, operands[2]);
+")
 
-(define_insn "*muldf_esfdf_esfdf"
-  [(set (match_operand:DF 0 "s_register_operand" "=f")
-       (mult:DF
-        (float_extend:DF (match_operand:SF 1 "s_register_operand" "f"))
-        (float_extend:DF (match_operand:SF 2 "s_register_operand" "f"))))]
+(define_expand "muldf3"
+  [(set (match_operand:DF          0 "s_register_operand" "")
+       (mult:DF (match_operand:DF 1 "s_register_operand" "")
+                (match_operand:DF 2 "arm_float_rhs_operand" "")))]
   "TARGET_ARM && TARGET_HARD_FLOAT"
-  "muf%?d\\t%0, %1, %2"
-  [(set_attr "type" "fmul")
-   (set_attr "predicable" "yes")]
-)
+  "
+  if (TARGET_MAVERICK
+      && !cirrus_fp_register (operands[2], DFmode))
+    operands[2] = force_reg (DFmode, operands[2]);
+")
 \f
 ;; Division insns
 
-(define_insn "divsf3"
-  [(set (match_operand:SF 0 "s_register_operand" "=f,f")
-       (div:SF (match_operand:SF 1 "fpu_rhs_operand" "f,G")
-               (match_operand:SF 2 "fpu_rhs_operand" "fG,f")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "@
-   fdv%?s\\t%0, %1, %2
-   frd%?s\\t%0, %2, %1"
-  [(set_attr "type" "fdivs")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "divdf3"
-  [(set (match_operand:DF 0 "s_register_operand" "=f,f")
-       (div:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G")
-               (match_operand:DF 2 "fpu_rhs_operand" "fG,f")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "@
-   dvf%?d\\t%0, %1, %2
-   rdf%?d\\t%0, %2, %1"
-  [(set_attr "type" "fdivd")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*divdf_esfdf_df"
-  [(set (match_operand:DF 0 "s_register_operand" "=f")
-       (div:DF (float_extend:DF
-                (match_operand:SF 1 "s_register_operand" "f"))
-               (match_operand:DF 2 "fpu_rhs_operand" "fG")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "dvf%?d\\t%0, %1, %2"
-  [(set_attr "type" "fdivd")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*divdf_df_esfdf"
-  [(set (match_operand:DF 0 "s_register_operand" "=f")
-       (div:DF (match_operand:DF 1 "fpu_rhs_operand" "fG")
-               (float_extend:DF
-                (match_operand:SF 2 "s_register_operand" "f"))))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "rdf%?d\\t%0, %2, %1"
-  [(set_attr "type" "fdivd")
-   (set_attr "predicable" "yes")]
-)
+(define_expand "divsf3"
+  [(set (match_operand:SF 0 "s_register_operand" "")
+       (div:SF (match_operand:SF 1 "arm_float_rhs_operand" "")
+               (match_operand:SF 2 "arm_float_rhs_operand" "")))]
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
+  "")
 
-(define_insn "*divdf_esfdf_esfdf"
-  [(set (match_operand:DF 0 "s_register_operand" "=f")
-       (div:DF (float_extend:DF
-                (match_operand:SF 1 "s_register_operand" "f"))
-               (float_extend:DF
-                (match_operand:SF 2 "s_register_operand" "f"))))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "dvf%?d\\t%0, %1, %2"
-  [(set_attr "type" "fdivd")
-   (set_attr "predicable" "yes")]
-)
+(define_expand "divdf3"
+  [(set (match_operand:DF 0 "s_register_operand" "")
+       (div:DF (match_operand:DF 1 "arm_float_rhs_operand" "")
+               (match_operand:DF 2 "arm_float_rhs_operand" "")))]
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
+  "")
 \f
 ;; Modulo insns
 
-(define_insn "modsf3"
-  [(set (match_operand:SF 0 "s_register_operand" "=f")
-       (mod:SF (match_operand:SF 1 "s_register_operand" "f")
-               (match_operand:SF 2 "fpu_rhs_operand" "fG")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "rmf%?s\\t%0, %1, %2"
-  [(set_attr "type" "fdivs")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "moddf3"
-  [(set (match_operand:DF 0 "s_register_operand" "=f")
-       (mod:DF (match_operand:DF 1 "s_register_operand" "f")
-               (match_operand:DF 2 "fpu_rhs_operand" "fG")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "rmf%?d\\t%0, %1, %2"
-  [(set_attr "type" "fdivd")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*moddf_esfdf_df"
-  [(set (match_operand:DF 0 "s_register_operand" "=f")
-       (mod:DF (float_extend:DF
-                (match_operand:SF 1 "s_register_operand" "f"))
-               (match_operand:DF 2 "fpu_rhs_operand" "fG")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "rmf%?d\\t%0, %1, %2"
-  [(set_attr "type" "fdivd")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*moddf_df_esfdf"
-  [(set (match_operand:DF 0 "s_register_operand" "=f")
-       (mod:DF (match_operand:DF 1 "s_register_operand" "f")
-               (float_extend:DF
-                (match_operand:SF 2 "s_register_operand" "f"))))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "rmf%?d\\t%0, %1, %2"
-  [(set_attr "type" "fdivd")
-   (set_attr "predicable" "yes")]
-)
+(define_expand "modsf3"
+  [(set (match_operand:SF 0 "s_register_operand" "")
+       (mod:SF (match_operand:SF 1 "s_register_operand" "")
+               (match_operand:SF 2 "arm_float_rhs_operand" "")))]
+  "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+  "")
 
-(define_insn "*moddf_esfdf_esfdf"
-  [(set (match_operand:DF 0 "s_register_operand" "=f")
-       (mod:DF (float_extend:DF
-                (match_operand:SF 1 "s_register_operand" "f"))
-               (float_extend:DF
-                (match_operand:SF 2 "s_register_operand" "f"))))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "rmf%?d\\t%0, %1, %2"
-  [(set_attr "type" "fdivd")
-   (set_attr "predicable" "yes")]
-)
+(define_expand "moddf3"
+  [(set (match_operand:DF 0 "s_register_operand" "")
+       (mod:DF (match_operand:DF 1 "s_register_operand" "")
+               (match_operand:DF 2 "arm_float_rhs_operand" "")))]
+  "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+  "")
 \f
 ;; Boolean and,ior,xor insns
 
        (match_operator:DI 6 "logical_binary_operator"
          [(match_operand:DI 1 "s_register_operand" "")
           (match_operand:DI 2 "s_register_operand" "")]))]
-  "TARGET_ARM && reload_completed"
+  "TARGET_ARM && reload_completed && ! IS_IWMMXT_REGNUM (REGNO (operands[0]))"
   [(set (match_dup 0) (match_op_dup:SI 6 [(match_dup 1) (match_dup 2)]))
    (set (match_dup 3) (match_op_dup:SI 6 [(match_dup 4) (match_dup 5)]))]
   "
   [(set (match_operand:DI         0 "s_register_operand" "=&r,&r")
        (and:DI (match_operand:DI 1 "s_register_operand"  "%0,r")
                (match_operand:DI 2 "s_register_operand"   "r,r")))]
-  "TARGET_ARM"
+  "TARGET_ARM && ! TARGET_IWMMXT"
   "#"
   [(set_attr "length" "8")]
 )
     {
       if (GET_CODE (operands[2]) == CONST_INT)
         {
-          arm_split_constant (AND, SImode, INTVAL (operands[2]), operands[0],
-                             operands[1],
-                             (no_new_pseudos
-                              ? 0 : preserve_subexpressions_p ()));
+          arm_split_constant (AND, SImode, NULL_RTX,
+                             INTVAL (operands[2]), operands[0],
+                             operands[1], optimize && !no_new_pseudos);
+
           DONE;
         }
     }
        || const_ok_for_arm (~INTVAL (operands[2])))"
   [(clobber (const_int 0))]
   "
-  arm_split_constant  (AND, SImode, INTVAL (operands[2]), operands[0],
-                      operands[1], 0);
+  arm_split_constant  (AND, SImode, curr_insn, 
+                      INTVAL (operands[2]), operands[0], operands[1], 0);
   DONE;
   "
   [(set_attr "length" "4,4,16")
   [(set_attr "conds" "set")]
 )
 
-(define_insn "*ne_zeroextractsi"
+(define_insn_and_split "*ne_zeroextractsi"
   [(set (match_operand:SI 0 "s_register_operand" "=r")
        (ne:SI (zero_extract:SI
                (match_operand:SI 1 "s_register_operand" "r")
        && INTVAL (operands[2]) > 0 
        && INTVAL (operands[2]) + (INTVAL (operands[3]) & 1) <= 8
        && INTVAL (operands[2]) + INTVAL (operands[3]) <= 32)"
-  "*
+  "#"
+  "TARGET_ARM
+   && (INTVAL (operands[3]) >= 0 && INTVAL (operands[3]) < 32
+       && INTVAL (operands[2]) > 0 
+       && INTVAL (operands[2]) + (INTVAL (operands[3]) & 1) <= 8
+       && INTVAL (operands[2]) + INTVAL (operands[3]) <= 32)"
+  [(parallel [(set (reg:CC_NOOV CC_REGNUM)
+                  (compare:CC_NOOV (and:SI (match_dup 1) (match_dup 2))
+                                   (const_int 0)))
+             (set (match_dup 0) (and:SI (match_dup 1) (match_dup 2)))])
+   (set (match_dup 0)
+       (if_then_else:SI (eq (reg:CC_NOOV CC_REGNUM) (const_int 0))
+                        (match_dup 0) (const_int 1)))]
+  "
   operands[2] = GEN_INT (((1 << INTVAL (operands[2])) - 1)
-                        << INTVAL (operands[3]));
-  output_asm_insn (\"ands\\t%0, %1, %2\", operands);
-  return \"movne\\t%0, #1\";
+                        << INTVAL (operands[3])); 
   "
   [(set_attr "conds" "clob")
    (set_attr "length" "8")]
 )
 
-;;; ??? This pattern is bogus.  If operand3 has bits outside the range
-;;; represented by the bitfield, then this will produce incorrect results.
-;;; Somewhere, the value needs to be truncated.  On targets like the m68k,
-;;; which have a real bit-field insert instruction, the truncation happens
-;;; in the bit-field insert instruction itself.  Since arm does not have a
-;;; bit-field insert instruction, we would have to emit code here to truncate
-;;; the value before we insert.  This loses some of the advantage of having
-;;; this insv pattern, so this pattern needs to be reevalutated.
-
-(define_expand "insv"
-  [(set (zero_extract:SI (match_operand:SI 0 "s_register_operand" "")
-                         (match_operand:SI 1 "general_operand" "")
-                         (match_operand:SI 2 "general_operand" ""))
-        (match_operand:SI 3 "reg_or_int_operand" ""))]
+(define_insn_and_split "*ne_zeroextractsi_shifted"
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
+       (ne:SI (zero_extract:SI
+               (match_operand:SI 1 "s_register_operand" "r")
+               (match_operand:SI 2 "const_int_operand" "n")
+               (const_int 0))
+              (const_int 0)))
+   (clobber (reg:CC CC_REGNUM))]
   "TARGET_ARM"
+  "#"
+  "TARGET_ARM"
+  [(parallel [(set (reg:CC_NOOV CC_REGNUM)
+                  (compare:CC_NOOV (ashift:SI (match_dup 1) (match_dup 2))
+                                   (const_int 0)))
+             (set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))])
+   (set (match_dup 0)
+       (if_then_else:SI (eq (reg:CC_NOOV CC_REGNUM) (const_int 0))
+                        (match_dup 0) (const_int 1)))]
   "
-  {
-    int start_bit = INTVAL (operands[2]);
-    int width = INTVAL (operands[1]);
-    HOST_WIDE_INT mask = (((HOST_WIDE_INT)1) << width) - 1;
-    rtx target, subtarget;
-
-    target = operands[0];
-    /* Avoid using a subreg as a subtarget, and avoid writing a paradoxical 
-       subreg as the final target.  */
-    if (GET_CODE (target) == SUBREG)
-      {
-       subtarget = gen_reg_rtx (SImode);
-       if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (target)))
-           < GET_MODE_SIZE (SImode))
-         target = SUBREG_REG (target);
-      }
-    else
-      subtarget = target;    
-
-    if (GET_CODE (operands[3]) == CONST_INT)
-      {
-       /* Since we are inserting a known constant, we may be able to
-          reduce the number of bits that we have to clear so that
-          the mask becomes simple.  */
-       /* ??? This code does not check to see if the new mask is actually
-          simpler.  It may not be.  */
-       rtx op1 = gen_reg_rtx (SImode);
-       /* ??? Truncate operand3 to fit in the bitfield.  See comment before
-          start of this pattern.  */
-       HOST_WIDE_INT op3_value = mask & INTVAL (operands[3]);
-       HOST_WIDE_INT mask2 = ((mask & ~op3_value) << start_bit);
+  operands[2] = GEN_INT (32 - INTVAL (operands[2]));
+  "
+  [(set_attr "conds" "clob")
+   (set_attr "length" "8")]
+)
 
-       emit_insn (gen_andsi3 (op1, operands[0], GEN_INT (~mask2)));
-       emit_insn (gen_iorsi3 (subtarget, op1,
-                              GEN_INT (op3_value << start_bit)));
+(define_insn_and_split "*ite_ne_zeroextractsi"
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
+       (if_then_else:SI (ne (zero_extract:SI
+                             (match_operand:SI 1 "s_register_operand" "r")
+                             (match_operand:SI 2 "const_int_operand" "n")
+                             (match_operand:SI 3 "const_int_operand" "n"))
+                            (const_int 0))
+                        (match_operand:SI 4 "arm_not_operand" "rIK")
+                        (const_int 0)))
+   (clobber (reg:CC CC_REGNUM))]
+  "TARGET_ARM
+   && (INTVAL (operands[3]) >= 0 && INTVAL (operands[3]) < 32
+       && INTVAL (operands[2]) > 0 
+       && INTVAL (operands[2]) + (INTVAL (operands[3]) & 1) <= 8
+       && INTVAL (operands[2]) + INTVAL (operands[3]) <= 32)
+   && !reg_overlap_mentioned_p (operands[0], operands[4])"
+  "#"
+  "TARGET_ARM
+   && (INTVAL (operands[3]) >= 0 && INTVAL (operands[3]) < 32
+       && INTVAL (operands[2]) > 0 
+       && INTVAL (operands[2]) + (INTVAL (operands[3]) & 1) <= 8
+       && INTVAL (operands[2]) + INTVAL (operands[3]) <= 32)
+   && !reg_overlap_mentioned_p (operands[0], operands[4])"
+  [(parallel [(set (reg:CC_NOOV CC_REGNUM)
+                  (compare:CC_NOOV (and:SI (match_dup 1) (match_dup 2))
+                                   (const_int 0)))
+             (set (match_dup 0) (and:SI (match_dup 1) (match_dup 2)))])
+   (set (match_dup 0)
+       (if_then_else:SI (eq (reg:CC_NOOV CC_REGNUM) (const_int 0))
+                        (match_dup 0) (match_dup 4)))]
+  "
+  operands[2] = GEN_INT (((1 << INTVAL (operands[2])) - 1)
+                        << INTVAL (operands[3])); 
+  "
+  [(set_attr "conds" "clob")
+   (set_attr "length" "8")]
+)
+
+(define_insn_and_split "*ite_ne_zeroextractsi_shifted"
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
+       (if_then_else:SI (ne (zero_extract:SI
+                             (match_operand:SI 1 "s_register_operand" "r")
+                             (match_operand:SI 2 "const_int_operand" "n")
+                             (const_int 0))
+                            (const_int 0))
+                        (match_operand:SI 3 "arm_not_operand" "rIK")
+                        (const_int 0)))
+   (clobber (reg:CC CC_REGNUM))]
+  "TARGET_ARM && !reg_overlap_mentioned_p (operands[0], operands[3])"
+  "#"
+  "TARGET_ARM && !reg_overlap_mentioned_p (operands[0], operands[3])"
+  [(parallel [(set (reg:CC_NOOV CC_REGNUM)
+                  (compare:CC_NOOV (ashift:SI (match_dup 1) (match_dup 2))
+                                   (const_int 0)))
+             (set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))])
+   (set (match_dup 0)
+       (if_then_else:SI (eq (reg:CC_NOOV CC_REGNUM) (const_int 0))
+                        (match_dup 0) (match_dup 3)))]
+  "
+  operands[2] = GEN_INT (32 - INTVAL (operands[2]));
+  "
+  [(set_attr "conds" "clob")
+   (set_attr "length" "8")]
+)
+
+(define_split
+  [(set (match_operand:SI 0 "s_register_operand" "")
+       (zero_extract:SI (match_operand:SI 1 "s_register_operand" "")
+                        (match_operand:SI 2 "const_int_operand" "")
+                        (match_operand:SI 3 "const_int_operand" "")))
+   (clobber (match_operand:SI 4 "s_register_operand" ""))]
+  "TARGET_THUMB"
+  [(set (match_dup 4) (ashift:SI (match_dup 1) (match_dup 2)))
+   (set (match_dup 0) (lshiftrt:SI (match_dup 4) (match_dup 3)))]
+  "{
+     HOST_WIDE_INT temp = INTVAL (operands[2]);
+
+     operands[2] = GEN_INT (32 - temp - INTVAL (operands[3]));
+     operands[3] = GEN_INT (32 - temp);
+   }"
+)
+
+(define_split
+  [(set (match_operand:SI 0 "s_register_operand" "")
+       (match_operator:SI 1 "shiftable_operator"
+        [(zero_extract:SI (match_operand:SI 2 "s_register_operand" "")
+                          (match_operand:SI 3 "const_int_operand" "")
+                          (match_operand:SI 4 "const_int_operand" ""))
+         (match_operand:SI 5 "s_register_operand" "")]))
+   (clobber (match_operand:SI 6 "s_register_operand" ""))]
+  "TARGET_ARM"
+  [(set (match_dup 6) (ashift:SI (match_dup 2) (match_dup 3)))
+   (set (match_dup 0)
+       (match_op_dup 1
+        [(lshiftrt:SI (match_dup 6) (match_dup 4))
+         (match_dup 5)]))]
+  "{
+     HOST_WIDE_INT temp = INTVAL (operands[3]);
+
+     operands[3] = GEN_INT (32 - temp - INTVAL (operands[4]));
+     operands[4] = GEN_INT (32 - temp);
+   }"
+)
+  
+(define_split
+  [(set (match_operand:SI 0 "s_register_operand" "")
+       (sign_extract:SI (match_operand:SI 1 "s_register_operand" "")
+                        (match_operand:SI 2 "const_int_operand" "")
+                        (match_operand:SI 3 "const_int_operand" "")))]
+  "TARGET_THUMB"
+  [(set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))
+   (set (match_dup 0) (ashiftrt:SI (match_dup 0) (match_dup 3)))]
+  "{
+     HOST_WIDE_INT temp = INTVAL (operands[2]);
+
+     operands[2] = GEN_INT (32 - temp - INTVAL (operands[3]));
+     operands[3] = GEN_INT (32 - temp);
+   }"
+)
+
+(define_split
+  [(set (match_operand:SI 0 "s_register_operand" "")
+       (match_operator:SI 1 "shiftable_operator"
+        [(sign_extract:SI (match_operand:SI 2 "s_register_operand" "")
+                          (match_operand:SI 3 "const_int_operand" "")
+                          (match_operand:SI 4 "const_int_operand" ""))
+         (match_operand:SI 5 "s_register_operand" "")]))
+   (clobber (match_operand:SI 6 "s_register_operand" ""))]
+  "TARGET_ARM"
+  [(set (match_dup 6) (ashift:SI (match_dup 2) (match_dup 3)))
+   (set (match_dup 0)
+       (match_op_dup 1
+        [(ashiftrt:SI (match_dup 6) (match_dup 4))
+         (match_dup 5)]))]
+  "{
+     HOST_WIDE_INT temp = INTVAL (operands[3]);
+
+     operands[3] = GEN_INT (32 - temp - INTVAL (operands[4]));
+     operands[4] = GEN_INT (32 - temp);
+   }"
+)
+  
+;;; ??? This pattern is bogus.  If operand3 has bits outside the range
+;;; represented by the bitfield, then this will produce incorrect results.
+;;; Somewhere, the value needs to be truncated.  On targets like the m68k,
+;;; which have a real bit-field insert instruction, the truncation happens
+;;; in the bit-field insert instruction itself.  Since arm does not have a
+;;; bit-field insert instruction, we would have to emit code here to truncate
+;;; the value before we insert.  This loses some of the advantage of having
+;;; this insv pattern, so this pattern needs to be reevalutated.
+
+(define_expand "insv"
+  [(set (zero_extract:SI (match_operand:SI 0 "s_register_operand" "")
+                         (match_operand:SI 1 "general_operand" "")
+                         (match_operand:SI 2 "general_operand" ""))
+        (match_operand:SI 3 "reg_or_int_operand" ""))]
+  "TARGET_ARM"
+  "
+  {
+    int start_bit = INTVAL (operands[2]);
+    int width = INTVAL (operands[1]);
+    HOST_WIDE_INT mask = (((HOST_WIDE_INT)1) << width) - 1;
+    rtx target, subtarget;
+
+    target = operands[0];
+    /* Avoid using a subreg as a subtarget, and avoid writing a paradoxical 
+       subreg as the final target.  */
+    if (GET_CODE (target) == SUBREG)
+      {
+       subtarget = gen_reg_rtx (SImode);
+       if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (target)))
+           < GET_MODE_SIZE (SImode))
+         target = SUBREG_REG (target);
+      }
+    else
+      subtarget = target;    
+
+    if (GET_CODE (operands[3]) == CONST_INT)
+      {
+       /* Since we are inserting a known constant, we may be able to
+          reduce the number of bits that we have to clear so that
+          the mask becomes simple.  */
+       /* ??? This code does not check to see if the new mask is actually
+          simpler.  It may not be.  */
+       rtx op1 = gen_reg_rtx (SImode);
+       /* ??? Truncate operand3 to fit in the bitfield.  See comment before
+          start of this pattern.  */
+       HOST_WIDE_INT op3_value = mask & INTVAL (operands[3]);
+       HOST_WIDE_INT mask2 = ((mask & ~op3_value) << start_bit);
+
+       emit_insn (gen_andsi3 (op1, operands[0], GEN_INT (~mask2)));
+       emit_insn (gen_iorsi3 (subtarget, op1,
+                              gen_int_mode (op3_value << start_bit, SImode)));
       }
     else if (start_bit == 0
             && !(const_ok_for_arm (mask)
        /* A Trick, since we are setting the bottom bits in the word,
           we can shift operand[3] up, operand[0] down, OR them together
           and rotate the result back again.  This takes 3 insns, and
-          the third might be mergable into another op.  */
+          the third might be mergeable into another op.  */
        /* The shift up copes with the possibility that operand[3] is
            wider than the bitfield.  */
        rtx op0 = gen_reg_rtx (SImode);
                (match_operand:DI 2 "s_register_operand" "0,r")))]
   "TARGET_ARM"
   "#"
-  "TARGET_ARM && reload_completed"
+  "TARGET_ARM && reload_completed && ! IS_IWMMXT_REGNUM (REGNO (operands[0]))"
   [(set (match_dup 0) (and:SI (not:SI (match_dup 1)) (match_dup 2)))
    (set (match_dup 3) (and:SI (not:SI (match_dup 4)) (match_dup 5)))]
   "
 )
 
 (define_insn "andsi_not_shiftsi_si"
-  [(set (match_operand:SI                   0 "s_register_operand" "=r")
-       (and:SI (not:SI (match_operator:SI  4 "shift_operator"
-                        [(match_operand:SI 2 "s_register_operand"  "r")
-                         (match_operand:SI 3 "arm_rhs_operand"     "rM")]))
-               (match_operand:SI           1 "s_register_operand"  "r")))]
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
+       (and:SI (not:SI (match_operator:SI 4 "shift_operator"
+                        [(match_operand:SI 2 "s_register_operand" "r")
+                         (match_operand:SI 3 "arm_rhs_operand" "rM")]))
+               (match_operand:SI 1 "s_register_operand" "r")))]
   "TARGET_ARM"
   "bic%?\\t%0, %1, %2%S4"
   [(set_attr "predicable" "yes")
    (set_attr "shift" "2")
-   ]
+   (set (attr "type") (if_then_else (match_operand 3 "const_int_operand" "")
+                     (const_string "alu_shift")
+                     (const_string "alu_shift_reg")))]
 )
 
 (define_insn "*andsi_notsi_si_compare0"
   [(set (match_operand:DI         0 "s_register_operand" "=&r,&r")
        (ior:DI (match_operand:DI 1 "s_register_operand"  "%0,r")
                (match_operand:DI 2 "s_register_operand"   "r,r")))]
-  "TARGET_ARM"
+  "TARGET_ARM && ! TARGET_IWMMXT"
   "#"
   [(set_attr "length" "8")
    (set_attr "predicable" "yes")]
     {
       if (TARGET_ARM)
         {
-          arm_split_constant (IOR, SImode, INTVAL (operands[2]), operands[0],
-                             operands[1],
-                             (no_new_pseudos
-                             ? 0 : preserve_subexpressions_p ()));
+          arm_split_constant (IOR, SImode, NULL_RTX,
+                             INTVAL (operands[2]), operands[0], operands[1],
+                             optimize && !no_new_pseudos);
           DONE;
        }
       else /* TARGET_THUMB */
    && !const_ok_for_arm (INTVAL (operands[2]))"
   [(clobber (const_int 0))]
   "
-  arm_split_constant (IOR, SImode, INTVAL (operands[2]), operands[0],
-                     operands[1], 0);
+  arm_split_constant (IOR, SImode, curr_insn, 
+                      INTVAL (operands[2]), operands[0], operands[1], 0);
   DONE;
   "
   [(set_attr "length" "4,16")
 
 (define_peephole2
   [(match_scratch:SI 3 "r")
-   (set (match_operand:SI         0 "s_register_operand" "")
-       (ior:SI (match_operand:SI 1 "s_register_operand" "")
+   (set (match_operand:SI 0 "arm_general_register_operand" "")
+       (ior:SI (match_operand:SI 1 "arm_general_register_operand" "")
                (match_operand:SI 2 "const_int_operand" "")))]
   "TARGET_ARM
    && !const_ok_for_arm (INTVAL (operands[2]))
   [(set (match_operand:DI         0 "s_register_operand" "=&r,&r")
        (xor:DI (match_operand:DI 1 "s_register_operand"  "%0,r")
                (match_operand:DI 2 "s_register_operand"   "r,r")))]
-  "TARGET_ARM"
+  "TARGET_ARM && !TARGET_IWMMXT"
   "#"
   [(set_attr "length" "8")
    (set_attr "predicable" "yes")]
    (set_attr "predicable" "yes")]
 )
 
+(define_split
+  [(set (match_operand:SI 0 "s_register_operand" "")
+       (match_operator:SI 1 "logical_binary_operator"
+        [(zero_extract:SI (match_operand:SI 2 "s_register_operand" "")
+                          (match_operand:SI 3 "const_int_operand" "")
+                          (match_operand:SI 4 "const_int_operand" ""))
+         (match_operator:SI 9 "logical_binary_operator"
+          [(lshiftrt:SI (match_operand:SI 5 "s_register_operand" "")
+                        (match_operand:SI 6 "const_int_operand" ""))
+           (match_operand:SI 7 "s_register_operand" "")])]))
+   (clobber (match_operand:SI 8 "s_register_operand" ""))]
+  "TARGET_ARM
+   && GET_CODE (operands[1]) == GET_CODE (operands[9])
+   && INTVAL (operands[3]) == 32 - INTVAL (operands[6])"
+  [(set (match_dup 8)
+       (match_op_dup 1
+        [(ashift:SI (match_dup 2) (match_dup 4))
+         (match_dup 5)]))
+   (set (match_dup 0)
+       (match_op_dup 1
+        [(lshiftrt:SI (match_dup 8) (match_dup 6))
+         (match_dup 7)]))]
+  "
+  operands[4] = GEN_INT (32 - (INTVAL (operands[3]) + INTVAL (operands[4])));
+")
+
+(define_split
+  [(set (match_operand:SI 0 "s_register_operand" "")
+       (match_operator:SI 1 "logical_binary_operator"
+        [(match_operator:SI 9 "logical_binary_operator"
+          [(lshiftrt:SI (match_operand:SI 5 "s_register_operand" "")
+                        (match_operand:SI 6 "const_int_operand" ""))
+           (match_operand:SI 7 "s_register_operand" "")])
+         (zero_extract:SI (match_operand:SI 2 "s_register_operand" "")
+                          (match_operand:SI 3 "const_int_operand" "")
+                          (match_operand:SI 4 "const_int_operand" ""))]))
+   (clobber (match_operand:SI 8 "s_register_operand" ""))]
+  "TARGET_ARM
+   && GET_CODE (operands[1]) == GET_CODE (operands[9])
+   && INTVAL (operands[3]) == 32 - INTVAL (operands[6])"
+  [(set (match_dup 8)
+       (match_op_dup 1
+        [(ashift:SI (match_dup 2) (match_dup 4))
+         (match_dup 5)]))
+   (set (match_dup 0)
+       (match_op_dup 1
+        [(lshiftrt:SI (match_dup 8) (match_dup 6))
+         (match_dup 7)]))]
+  "
+  operands[4] = GEN_INT (32 - (INTVAL (operands[3]) + INTVAL (operands[4])));
+")
+
+(define_split
+  [(set (match_operand:SI 0 "s_register_operand" "")
+       (match_operator:SI 1 "logical_binary_operator"
+        [(sign_extract:SI (match_operand:SI 2 "s_register_operand" "")
+                          (match_operand:SI 3 "const_int_operand" "")
+                          (match_operand:SI 4 "const_int_operand" ""))
+         (match_operator:SI 9 "logical_binary_operator"
+          [(ashiftrt:SI (match_operand:SI 5 "s_register_operand" "")
+                        (match_operand:SI 6 "const_int_operand" ""))
+           (match_operand:SI 7 "s_register_operand" "")])]))
+   (clobber (match_operand:SI 8 "s_register_operand" ""))]
+  "TARGET_ARM
+   && GET_CODE (operands[1]) == GET_CODE (operands[9])
+   && INTVAL (operands[3]) == 32 - INTVAL (operands[6])"
+  [(set (match_dup 8)
+       (match_op_dup 1
+        [(ashift:SI (match_dup 2) (match_dup 4))
+         (match_dup 5)]))
+   (set (match_dup 0)
+       (match_op_dup 1
+        [(ashiftrt:SI (match_dup 8) (match_dup 6))
+         (match_dup 7)]))]
+  "
+  operands[4] = GEN_INT (32 - (INTVAL (operands[3]) + INTVAL (operands[4])));
+")
+
+(define_split
+  [(set (match_operand:SI 0 "s_register_operand" "")
+       (match_operator:SI 1 "logical_binary_operator"
+        [(match_operator:SI 9 "logical_binary_operator"
+          [(ashiftrt:SI (match_operand:SI 5 "s_register_operand" "")
+                        (match_operand:SI 6 "const_int_operand" ""))
+           (match_operand:SI 7 "s_register_operand" "")])
+         (sign_extract:SI (match_operand:SI 2 "s_register_operand" "")
+                          (match_operand:SI 3 "const_int_operand" "")
+                          (match_operand:SI 4 "const_int_operand" ""))]))
+   (clobber (match_operand:SI 8 "s_register_operand" ""))]
+  "TARGET_ARM
+   && GET_CODE (operands[1]) == GET_CODE (operands[9])
+   && INTVAL (operands[3]) == 32 - INTVAL (operands[6])"
+  [(set (match_dup 8)
+       (match_op_dup 1
+        [(ashift:SI (match_dup 2) (match_dup 4))
+         (match_dup 5)]))
+   (set (match_dup 0)
+       (match_op_dup 1
+        [(ashiftrt:SI (match_dup 8) (match_dup 6))
+         (match_dup 7)]))]
+  "
+  operands[4] = GEN_INT (32 - (INTVAL (operands[3]) + INTVAL (operands[4])));
+")
 \f
 
 ;; Minimum and maximum insns
    (clobber (reg:CC CC_REGNUM))]
   "TARGET_ARM"
   "*
-  operands[3] = gen_rtx (minmax_code (operands[3]), SImode, operands[1],
-                        operands[2]);
+  operands[3] = gen_rtx_fmt_ee (minmax_code (operands[3]), SImode,
+                               operands[1], operands[2]);
   output_asm_insn (\"cmp\\t%1, %2\", operands);
   output_asm_insn (\"str%d3\\t%1, %0\", operands);
   output_asm_insn (\"str%D3\\t%2, %0\", operands);
            (match_operand:SI 3 "arm_rhs_operand" "rI,rI")])
          (match_operand:SI 1 "s_register_operand" "0,?r")]))
    (clobber (reg:CC CC_REGNUM))]
-  "TARGET_ARM
-   && (GET_CODE (operands[1]) != REG
-       || (REGNO(operands[1]) != FRAME_POINTER_REGNUM
-           && REGNO(operands[1]) != ARG_POINTER_REGNUM))"
+  "TARGET_ARM && !arm_eliminable_register (operands[1])"
   "*
   {
     enum rtx_code code = GET_CODE (operands[4]);
 
-    operands[5] = gen_rtx (minmax_code (operands[5]), SImode, operands[2],
-                          operands[3]);
+    operands[5] = gen_rtx_fmt_ee (minmax_code (operands[5]), SImode,
+                                 operands[2], operands[3]);
     output_asm_insn (\"cmp\\t%2, %3\", operands);
     output_asm_insn (\"%i4%d5\\t%0, %1, %2\", operands);
     if (which_alternative != 0 || operands[3] != const0_rtx
 \f
 ;; 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_HARD_FLOAT && TARGET_MAVERICK))
+    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" "")
   [(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" "")
   [(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" "")
   [(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_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"
   [(set (match_operand:SI   0 "s_register_operand" "=r")
        (match_operator:SI  3 "shift_operator"
   "mov%?\\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")))]
 )
 
 (define_insn "*shiftsi3_compare0"
   "mov%?s\\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")))]
 )
 
 (define_insn "*shiftsi3_compare0_scratch"
   "TARGET_ARM"
   "mov%?s\\t%0, %1%S3"
   [(set_attr "conds" "set")
-   (set_attr "shift" "1")
-   ]
+   (set_attr "shift" "1")]
 )
 
 (define_insn "*notsi_shiftsi"
   "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")))]
 )
 
 (define_insn "*notsi_shiftsi_compare0"
   "mvn%?s\\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")))]
 )
 
 (define_insn "*not_shiftsi_compare0_scratch"
   "mvn%?s\\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")))]
 )
 
 ;; We don't really have extzv, but defining this using shifts helps
   [(set_attr "length" "2")]
 )
 
-(define_insn "*arm_negsf2"
-  [(set (match_operand:SF         0 "s_register_operand" "=f")
-       (neg:SF (match_operand:SF 1 "s_register_operand" "f")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "mnf%?s\\t%0, %1"
-  [(set_attr "type" "ffarith")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*arm_negdf2"
-  [(set (match_operand:DF         0 "s_register_operand" "=f")
-       (neg:DF (match_operand:DF 1 "s_register_operand" "f")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "mnf%?d\\t%0, %1"
-  [(set_attr "type" "ffarith")
-   (set_attr "predicable" "yes")]
+(define_expand "negsf2"
+  [(set (match_operand:SF         0 "s_register_operand" "")
+       (neg:SF (match_operand:SF 1 "s_register_operand" "")))]
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
+  ""
 )
 
-(define_insn "*negdf_esfdf"
-  [(set (match_operand:DF 0 "s_register_operand" "=f")
-       (neg:DF (float_extend:DF
-                (match_operand:SF 1 "s_register_operand" "f"))))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "mnf%?d\\t%0, %1"
-  [(set_attr "type" "ffarith")
-   (set_attr "predicable" "yes")]
-)
+(define_expand "negdf2"
+  [(set (match_operand:DF         0 "s_register_operand" "")
+       (neg:DF (match_operand:DF 1 "s_register_operand" "")))]
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
+  "")
 
 ;; abssi2 doesn't really clobber the condition codes if a different register
 ;; is being set.  To keep things simple, assume during rtl manipulations that
 ;; it does, but tell the final scan operator the truth.  Similarly for
 ;; (neg (abs...))
 
+(define_expand "abssi2"
+  [(parallel
+    [(set (match_operand:SI         0 "s_register_operand" "")
+         (abs:SI (match_operand:SI 1 "s_register_operand" "")))
+     (clobber (reg:CC CC_REGNUM))])]
+  "TARGET_ARM"
+  "")
+
 (define_insn "*arm_abssi2"
   [(set (match_operand:SI         0 "s_register_operand" "=r,&r")
        (abs:SI (match_operand:SI 1 "s_register_operand" "0,r")))
    (set_attr "length" "8")]
 )
 
-(define_insn "*arm_abssf2"
-  [(set (match_operand:SF          0 "s_register_operand" "=f")
-        (abs:SF (match_operand:SF 1 "s_register_operand" "f")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "abs%?s\\t%0, %1"
-  [(set_attr "type" "ffarith")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*arm_absdf2"
-  [(set (match_operand:DF         0 "s_register_operand" "=f")
-       (abs:DF (match_operand:DF 1 "s_register_operand" "f")))]
+(define_expand "abssf2"
+  [(set (match_operand:SF         0 "s_register_operand" "")
+       (abs:SF (match_operand:SF 1 "s_register_operand" "")))]
   "TARGET_ARM && TARGET_HARD_FLOAT"
-  "abs%?d\\t%0, %1"
-  [(set_attr "type" "ffarith")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*absdf_esfdf"
-  [(set (match_operand:DF 0 "s_register_operand" "=f")
-       (abs:DF (float_extend:DF
-                (match_operand:SF 1 "s_register_operand" "f"))))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "abs%?d\\t%0, %1"
-  [(set_attr "type" "ffarith")
-   (set_attr "predicable" "yes")]
-)
+  "")
 
-(define_insn "sqrtsf2"
-  [(set (match_operand:SF 0 "s_register_operand" "=f")
-       (sqrt:SF (match_operand:SF 1 "s_register_operand" "f")))]
+(define_expand "absdf2"
+  [(set (match_operand:DF         0 "s_register_operand" "")
+       (abs:DF (match_operand:DF 1 "s_register_operand" "")))]
   "TARGET_ARM && TARGET_HARD_FLOAT"
-  "sqt%?s\\t%0, %1"
-  [(set_attr "type" "float_em")
-   (set_attr "predicable" "yes")]
-)
+  "")
 
-(define_insn "sqrtdf2"
-  [(set (match_operand:DF 0 "s_register_operand" "=f")
-       (sqrt:DF (match_operand:DF 1 "s_register_operand" "f")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "sqt%?d\\t%0, %1"
-  [(set_attr "type" "float_em")
-   (set_attr "predicable" "yes")]
-)
+(define_expand "sqrtsf2"
+  [(set (match_operand:SF 0 "s_register_operand" "")
+       (sqrt:SF (match_operand:SF 1 "s_register_operand" "")))]
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
+  "")
 
-(define_insn "*sqrtdf_esfdf"
-  [(set (match_operand:DF 0 "s_register_operand" "=f")
-       (sqrt:DF (float_extend:DF
-                 (match_operand:SF 1 "s_register_operand" "f"))))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "sqt%?d\\t%0, %1"
-  [(set_attr "type" "float_em")
-   (set_attr "predicable" "yes")]
-)
+(define_expand "sqrtdf2"
+  [(set (match_operand:DF 0 "s_register_operand" "")
+       (sqrt:DF (match_operand:DF 1 "s_register_operand" "")))]
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
+  "")
 
 (define_insn_and_split "one_cmpldi2"
   [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
 \f
 ;; Fixed <--> Floating conversion insns
 
-(define_insn "*arm_floatsisf2"
-  [(set (match_operand:SF           0 "s_register_operand" "=f")
-       (float:SF (match_operand:SI 1 "s_register_operand" "r")))]
+(define_expand "floatsisf2"
+  [(set (match_operand:SF           0 "s_register_operand" "")
+       (float:SF (match_operand:SI 1 "s_register_operand" "")))]
   "TARGET_ARM && TARGET_HARD_FLOAT"
-  "flt%?s\\t%0, %1"
-  [(set_attr "type" "r_2_f")
-   (set_attr "predicable" "yes")]
-)
+  "
+  if (TARGET_MAVERICK)
+    {
+      emit_insn (gen_cirrus_floatsisf2 (operands[0], operands[1]));
+      DONE;
+    }
+")
 
-(define_insn "*arm_floatsidf2"
-  [(set (match_operand:DF           0 "s_register_operand" "=f")
-       (float:DF (match_operand:SI 1 "s_register_operand" "r")))]
+(define_expand "floatsidf2"
+  [(set (match_operand:DF           0 "s_register_operand" "")
+       (float:DF (match_operand:SI 1 "s_register_operand" "")))]
   "TARGET_ARM && TARGET_HARD_FLOAT"
-  "flt%?d\\t%0, %1"
-  [(set_attr "type" "r_2_f")
-   (set_attr "predicable" "yes")]
-)
+  "
+  if (TARGET_MAVERICK)
+    {
+      emit_insn (gen_cirrus_floatsidf2 (operands[0], operands[1]));
+      DONE;
+    }
+")
 
-(define_insn "*arm_fix_truncsfsi2"
-  [(set (match_operand:SI         0 "s_register_operand" "=r")
-       (fix:SI (match_operand:SF 1 "s_register_operand" "f")))]
+(define_expand "fix_truncsfsi2"
+  [(set (match_operand:SI         0 "s_register_operand" "")
+       (fix:SI (fix:SF (match_operand:SF 1 "s_register_operand"  ""))))]
   "TARGET_ARM && TARGET_HARD_FLOAT"
-  "fix%?z\\t%0, %1"
-  [(set_attr "type" "f_2_r")
-   (set_attr "predicable" "yes")]
-)
+  "
+  if (TARGET_MAVERICK)
+    {
+      if (!cirrus_fp_register (operands[0], SImode))
+        operands[0] = force_reg (SImode, operands[0]);
+      if (!cirrus_fp_register (operands[1], SFmode))
+        operands[1] = force_reg (SFmode, operands[0]);
+      emit_insn (gen_cirrus_truncsfsi2 (operands[0], operands[1]));
+      DONE;
+    }
+")
 
-(define_insn "*arm_fix_truncdfsi2"
-  [(set (match_operand:SI         0 "s_register_operand" "=r")
-       (fix:SI (match_operand:DF 1 "s_register_operand" "f")))]
+(define_expand "fix_truncdfsi2"
+  [(set (match_operand:SI         0 "s_register_operand" "")
+       (fix:SI (fix:DF (match_operand:DF 1 "s_register_operand"  ""))))]
   "TARGET_ARM && TARGET_HARD_FLOAT"
-  "fix%?z\\t%0, %1"
-  [(set_attr "type" "f_2_r")
-   (set_attr "predicable" "yes")]
-)
+  "
+  if (TARGET_MAVERICK)
+    {
+      if (!cirrus_fp_register (operands[1], DFmode))
+        operands[1] = force_reg (DFmode, operands[0]);
+      emit_insn (gen_cirrus_truncdfsi2 (operands[0], operands[1]));
+      DONE;
+    }
+")
 
 ;; Truncation insns
 
-(define_insn "*arm_truncdfsf2"
-  [(set (match_operand:SF 0 "s_register_operand" "=f")
+(define_expand "truncdfsf2"
+  [(set (match_operand:SF  0 "s_register_operand" "")
        (float_truncate:SF
-        (match_operand:DF 1 "s_register_operand" "f")))]
+        (match_operand:DF 1 "s_register_operand" "")))]
   "TARGET_ARM && TARGET_HARD_FLOAT"
-  "mvf%?s\\t%0, %1"
-  [(set_attr "type" "ffarith")
-   (set_attr "predicable" "yes")]
+  ""
 )
 \f
 ;; Zero and sign extension instructions.
    ldr%?b\\t%Q0, %1\;mov%?\\t%R0, #0"
   [(set_attr "length" "8")
    (set_attr "predicable" "yes")
-   (set_attr "type" "*,load")
+   (set_attr "type" "*,load_byte")
    (set_attr "pool_range" "*,4092")
    (set_attr "neg_pool_range" "*,4084")]
 )
   "TARGET_EITHER"
   "
   {
-    if (TARGET_ARM)
+    if ((TARGET_THUMB || arm_arch4) && GET_CODE (operands[1]) == MEM)
       {
-        if (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
-             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_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]);
-        operands[1] = gen_lowpart (SImode, operands[1]);
-        operands[2] = gen_reg_rtx (SImode);
+       emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+                               gen_rtx_ZERO_EXTEND (SImode, operands[1])));
+       DONE;
       }
-    else /* TARGET_THUMB */
-      {
-        if (GET_CODE (operands[1]) == MEM)
-         {
-           rtx tmp;
 
-           tmp = gen_rtx_ZERO_EXTEND (SImode, operands[1]);
-           tmp = gen_rtx_SET (VOIDmode, operands[0], tmp);
-           emit_insn (tmp);
-         }
-       else
-         {
-           rtx ops[3];
-           
-           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);
-           
-           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])));
+    if (TARGET_ARM && GET_CODE (operands[1]) == MEM)
+      {
+       emit_insn (gen_movhi_bytes (operands[0], operands[1]));
+       DONE;
+      }
 
-           ops[0] = operands[0];
-           ops[1] = operands[2];
-           ops[2] = GEN_INT (16);
+    if (!s_register_operand (operands[1], HImode))
+      operands[1] = copy_to_mode_reg (HImode, operands[1]);
 
-           emit_insn (gen_rtx_SET (VOIDmode, ops[0],
-                                   gen_rtx_LSHIFTRT (SImode, ops[1],
-                                                     ops[2])));
-         }
-       DONE; 
+    if (arm_arch6)
+      {
+       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"
+  [(set (match_operand:SI 0 "register_operand" "=l")
+       (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
+  "TARGET_THUMB && !arm_arch6"
   "*
   rtx mem = XEXP (operands[1], 0);
 
   return \"ldrh\\t%0, %1\";
   "
   [(set_attr "length" "4")
-   (set_attr "type" "load")
+   (set_attr "type" "load_byte")
    (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_arch6"
+  "*
+  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"
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
+       (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
+  "TARGET_ARM && arm_arch4 && !arm_arch6"
   "ldr%?h\\t%0, %1"
-  [(set_attr "type" "load")
+  [(set_attr "type" "load_byte")
    (set_attr "predicable" "yes")
    (set_attr "pool_range" "256")
    (set_attr "neg_pool_range" "244")]
 )
 
-(define_split
-  [(set (match_operand:SI 0 "s_register_operand" "")
-       (zero_extend:SI (match_operand:HI 1 "alignable_memory_operand" "")))
-   (clobber (match_operand:SI 2 "s_register_operand" ""))]
-  "TARGET_ARM && (!arm_arch4)"
-  [(set (match_dup 2) (match_dup 1))
-   (set (match_dup 0) (lshiftrt:SI (match_dup 2) (const_int 16)))]
-  "
-  if ((operands[1] = arm_gen_rotated_half_load (operands[1])) == NULL)
-    FAIL;
-  "
+(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_arch6"
+  "@
+   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_split
-  [(set (match_operand:SI 0 "s_register_operand" "")
-       (match_operator:SI 3 "shiftable_operator"
-        [(zero_extend:SI (match_operand:HI 1 "alignable_memory_operand" ""))
-         (match_operand:SI 4 "s_register_operand" "")]))
-   (clobber (match_operand:SI 2 "s_register_operand" ""))]
-  "TARGET_ARM && (!arm_arch4)"
-  [(set (match_dup 2) (match_dup 1))
-   (set (match_dup 0)
-       (match_op_dup 3
-        [(lshiftrt:SI (match_dup 2) (const_int 16)) (match_dup 4)]))]
-  "
-  if ((operands[1] = arm_gen_rotated_half_load (operands[1])) == NULL)
-    FAIL;
-  "
+(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_arch6"
+  "uxtah%?\\t%0, %2, %1"
+  [(set_attr "type" "alu_shift")
+   (set_attr "predicable" "yes")]
 )
 
 (define_expand "zero_extendqisi2"
        (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
   "TARGET_EITHER"
   "
-  if (GET_CODE (operands[1]) != MEM)
+  if (!arm_arch6 && GET_CODE (operands[1]) != MEM)
     {
       if (TARGET_ARM)
         {
 )
 
 (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"
+  [(set (match_operand:SI 0 "register_operand" "=l")
+       (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
+  "TARGET_THUMB && !arm_arch6"
   "ldrb\\t%0, %1"
   [(set_attr "length" "2")
-   (set_attr "type" "load")
+   (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_arch6"
+  "@
+   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"
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
+       (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
+  "TARGET_ARM && !arm_arch6"
   "ldr%?b\\t%0, %1\\t%@ zero_extendqisi2"
-  [(set_attr "type" "load")
+  [(set_attr "type" "load_byte")
    (set_attr "predicable" "yes")
    (set_attr "pool_range" "4096")
    (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_arch6"
+  "@
+   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_arch6"
+  "uxtab%?\\t%0, %2, %1"
+  [(set_attr "predicable" "yes")
+   (set_attr "type" "alu_shift")]
+)
+
 (define_split
   [(set (match_operand:SI 0 "s_register_operand" "")
        (zero_extend:SI (subreg:QI (match_operand:SI 1 "" "") 0)))
   "TARGET_EITHER"
   "
   {
-    if (TARGET_ARM && arm_arch4 && GET_CODE (operands[1]) == MEM)
+    if (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
-         rather than an LDR instruction, so we cannot get an unaligned
-         word access.  */
-        emit_insn (gen_rtx_SET (VOIDmode, operands[0],
-                  gen_rtx_SIGN_EXTEND (SImode, operands[1])));
-        DONE;
+       if (TARGET_THUMB)
+         {
+           emit_insn (gen_thumb_extendhisi2 (operands[0], operands[1]));
+           DONE;
+          }
+       else if (arm_arch4)
+         {
+           emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+                      gen_rtx_SIGN_EXTEND (SImode, operands[1])));
+           DONE;
+         }
       }
 
-    if (TARGET_ARM && TARGET_MMU_TRAPS && GET_CODE (operands[1]) == MEM)
+    if (TARGET_ARM && 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]);
-    operands[1] = gen_lowpart (SImode, operands[1]);
-    operands[2] = gen_reg_rtx (SImode);
 
-    if (TARGET_THUMB)
+    if (arm_arch6)
       {
-       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])));
-       
+       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_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"
+(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_arch6"
   "*
   {
     rtx ops[4];
         ops[1] = mem;
         ops[2] = const0_rtx;
       }
-      
-    if (GET_CODE (ops[1]) != REG)
-      {
-        debug_rtx (ops[1]);
-        abort ();
-      }
+
+    gcc_assert (GET_CODE (ops[1]) == REG);
 
     ops[0] = operands[0];
     ops[3] = operands[2];
     return \"\";
   }"
   [(set_attr "length" "4")
-   (set_attr "type" "load")
+   (set_attr "type" "load_byte")
    (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 us to die 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_arch6"
+  "*
+  {
+    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;
+      }
+      
+    gcc_assert (GET_CODE (ops[1]) == REG);
+
+    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)
     rtx mem1, mem2;
     rtx addr = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
 
-    mem1 = gen_rtx_MEM (QImode, addr);
-    MEM_COPY_ATTRIBUTES (mem1, operands[1]);
-    mem2 = gen_rtx_MEM (QImode, plus_constant (addr, 1));
-    MEM_COPY_ATTRIBUTES (mem2, operands[1]);
+    mem1 = change_address (operands[1], QImode, addr);
+    mem2 = change_address (operands[1], QImode, plus_constant (addr, 1));
     operands[0] = gen_lowpart (SImode, operands[0]);
     operands[1] = mem1;
     operands[2] = gen_reg_rtx (SImode);
   }"
 )
 
-(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"
+(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_arch6"
   "ldr%?sh\\t%0, %1"
-  [(set_attr "type" "load")
+  [(set_attr "type" "load_byte")
    (set_attr "predicable" "yes")
    (set_attr "pool_range" "256")
    (set_attr "neg_pool_range" "244")]
 )
 
-(define_split
-  [(set (match_operand:SI                 0 "s_register_operand" "")
-       (sign_extend:SI (match_operand:HI 1 "alignable_memory_operand" "")))
-   (clobber (match_operand:SI             2 "s_register_operand" ""))]
-  "TARGET_ARM && (!arm_arch4)"
-  [(set (match_dup 2) (match_dup 1))
-   (set (match_dup 0) (ashiftrt:SI (match_dup 2) (const_int 16)))]
-  "
-  if ((operands[1] = arm_gen_rotated_half_load (operands[1])) == NULL)
-    FAIL;
-  "
+(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_arch6"
+  "@
+   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_split
-  [(set (match_operand:SI                   0 "s_register_operand" "")
-       (match_operator:SI                  3 "shiftable_operator"
-        [(sign_extend:SI (match_operand:HI 1 "alignable_memory_operand" ""))
-         (match_operand:SI                 4 "s_register_operand" "")]))
-   (clobber (match_operand:SI               2 "s_register_operand" ""))]
-  "TARGET_ARM && (!arm_arch4)"
-  [(set (match_dup 2) (match_dup 1))
-   (set (match_dup 0)
-       (match_op_dup 3
-        [(ashiftrt:SI (match_dup 2) (const_int 16)) (match_dup 4)]))]
-  "if ((operands[1] = arm_gen_rotated_half_load (operands[1])) == NULL)
-     FAIL;
-  "
+(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_arch6"
+  "sxtah%?\\t%0, %2, %1"
 )
 
 (define_expand "extendqihi2"
   }"
 )
 
-; 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 "*extendqihi_insn"
-  [(set (match_operand:HI                 0 "s_register_operand" "=r")
-       (sign_extend:HI (match_operand:QI 1 "memory_operand"      "m")))]
+  [(set (match_operand:HI 0 "s_register_operand" "=r")
+       (sign_extend:HI (match_operand:QI 1 "memory_operand" "Uq")))]
   "TARGET_ARM && arm_arch4"
-  "*
-  /* 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" "load")
+  "ldr%?sb\\t%0, %1"
+  [(set_attr "type" "load_byte")
    (set_attr "predicable" "yes")
-   (set_attr "length" "8")
    (set_attr "pool_range" "256")
    (set_attr "neg_pool_range" "244")]
 )
 
-(define_split
-  [(set (match_operand:HI 0 "s_register_operand" "")
-       (sign_extend:HI (match_operand:QI 1 "bad_signed_byte_operand" "")))]
-  "TARGET_ARM && arm_arch4 && reload_completed"
-  [(set (match_dup 3) (match_dup 1))
-   (set (match_dup 0) (sign_extend:HI (match_dup 2)))]
-  "
-  {
-    HOST_WIDE_INT offset;
-
-    operands[3] = gen_rtx_REG (SImode, REGNO (operands[0]));
-    operands[2] = gen_rtx_MEM (QImode, operands[3]);
-    MEM_COPY_ATTRIBUTES (operands[2], operands[1]);
-    operands[1] = XEXP (operands[1], 0);
-    if (GET_CODE (operands[1]) == PLUS
-       && GET_CODE (XEXP (operands[1], 1)) == CONST_INT
-       && !(const_ok_for_arm (offset = INTVAL (XEXP (operands[1], 1)))
-            || const_ok_for_arm (-offset)))
-      {
-       HOST_WIDE_INT low = (offset > 0
-                            ? (offset & 0xff) : -((-offset) & 0xff));
-       XEXP (operands[2], 0) = plus_constant (operands[3], low);
-       operands[1] = plus_constant (XEXP (operands[1], 0), offset - low);
-      }
-    /* Ensure the sum is in correct canonical form */
-    else if (GET_CODE (operands[1]) == PLUS
-            && GET_CODE (XEXP (operands[1], 1)) != CONST_INT
-            && !s_register_operand (XEXP (operands[1], 1), VOIDmode))
-      operands[1] = gen_rtx_PLUS (GET_MODE (operands[1]),
-                                          XEXP (operands[1], 1),
-                                          XEXP (operands[1], 0));
-  }"
-)
-
 (define_expand "extendqisi2"
   [(set (match_dup 2)
        (ashift:SI (match_operand:QI 1 "general_operand" "")
   "TARGET_EITHER"
   "
   {
-    if (TARGET_ARM && arm_arch4 && GET_CODE (operands[1]) == MEM)
+    if ((TARGET_THUMB || arm_arch4) && GET_CODE (operands[1]) == MEM)
       {
-        emit_insn (gen_rtx_SET (VOIDmode,
-                               operands[0],
+        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]);
-    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;
+    if (arm_arch6)
+      {
+        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_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))
-    return \"#\";
-  return \"ldr%?sb\\t%0, %1\";
-  "
-  [(set_attr "type" "load")
+(define_insn "*arm_extendqisi"
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
+       (sign_extend:SI (match_operand:QI 1 "memory_operand" "Uq")))]
+  "TARGET_ARM && arm_arch4 && !arm_arch6"
+  "ldr%?sb\\t%0, %1"
+  [(set_attr "type" "load_byte")
    (set_attr "predicable" "yes")
-   (set_attr "length" "8")
    (set_attr "pool_range" "256")
    (set_attr "neg_pool_range" "244")]
 )
 
-(define_split
-  [(set (match_operand:SI 0 "s_register_operand" "")
-       (sign_extend:SI (match_operand:QI 1 "bad_signed_byte_operand" "")))]
-  "TARGET_ARM && arm_arch4 && reload_completed"
-  [(set (match_dup 0) (match_dup 1))
-   (set (match_dup 0) (sign_extend:SI (match_dup 2)))]
-  "
-  {
-    HOST_WIDE_INT offset;
-
-    operands[2] = gen_rtx_MEM (QImode, operands[0]);
-    MEM_COPY_ATTRIBUTES (operands[2], operands[1]);
-    operands[1] = XEXP (operands[1], 0);
-    if (GET_CODE (operands[1]) == PLUS
-       && GET_CODE (XEXP (operands[1], 1)) == CONST_INT
-       && !(const_ok_for_arm (offset = INTVAL (XEXP (operands[1], 1)))
-            || const_ok_for_arm (-offset)))
-      {
-       HOST_WIDE_INT low = (offset > 0
-                            ? (offset & 0xff) : -((-offset) & 0xff));
-       XEXP (operands[2], 0) = plus_constant (operands[0], low);
-       operands[1] = plus_constant (XEXP (operands[1], 0), offset - low);
-      }
-    /* Ensure the sum is in correct canonical form */
-    else if (GET_CODE (operands[1]) == PLUS
-            && GET_CODE (XEXP (operands[1], 1)) != CONST_INT
-            && !s_register_operand (XEXP (operands[1], 1), VOIDmode))
-      operands[1] = gen_rtx_PLUS (GET_MODE (operands[1]),
-                                          XEXP (operands[1], 1),
-                                          XEXP (operands[1], 0));
-  }"
+(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,Uq")))]
+  "TARGET_ARM && arm_arch6"
+  "@
+   sxtb%?\\t%0, %1
+   ldr%?sb\\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 "*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"
+(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_arch6"
+  "sxtab%?\\t%0, %2, %1"
+  [(set_attr "type" "alu_shift")
+   (set_attr "predicable" "yes")]
+)
+
+(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_arch6"
   "*
   {
     rtx ops[3];
            else
               output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops);
          }
-        else if (GET_CODE (b) != REG)
-         abort ();
        else
           {
+           gcc_assert (GET_CODE (b) == REG);
             if (REGNO (b) == REGNO (ops[0]))
              {
                 output_asm_insn (\"ldrb\\t%0, [%2, %1]\", ops);
     return \"\";
   }"
   [(set_attr "length" "2,6")
-   (set_attr "type" "load,load")
+   (set_attr "type" "load_byte,load_byte")
    (set_attr "pool_range" "32,32")]
 )
 
-(define_insn "*arm_extendsfdf2"
-  [(set (match_operand:DF                  0 "s_register_operand" "=f")
-       (float_extend:DF (match_operand:SF 1 "s_register_operand"  "f")))]
+(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_arch6"
+  "*
+  {
+    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
+          {
+           gcc_assert (GET_CODE (b) == REG);
+            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"
+  [(set (match_operand:DF                  0 "s_register_operand" "")
+       (float_extend:DF (match_operand:SF 1 "s_register_operand"  "")))]
   "TARGET_ARM && TARGET_HARD_FLOAT"
-  "mvf%?d\\t%0, %1"
-  [(set_attr "type" "ffarith")
-   (set_attr "predicable" "yes")]
+  ""
 )
 \f
 ;; Move insns (including loads and stores)
 )
 
 (define_insn "*arm_movdi"
-  [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r, r, o<>")
-       (match_operand:DI 1 "di_operand"              "rIK,mi,r"))]
-  "TARGET_ARM && !TARGET_CIRRUS"
+  [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r, r, r, r, m")
+       (match_operand:DI 1 "di_operand"              "rDa,Db,Dc,mi,r"))]
+  "TARGET_ARM
+  && !(TARGET_HARD_FLOAT && (TARGET_MAVERICK || TARGET_VFP))
+  && !TARGET_IWMMXT"
   "*
-  return (output_move_double (operands));
+  switch (which_alternative)
+    {
+    case 0:
+    case 1:
+    case 2:
+      return \"#\";
+    default:
+      return output_move_double (operands);
+    }
+  "
+  [(set_attr "length" "8,12,16,8,8")
+   (set_attr "type" "*,*,*,load2,store2")
+   (set_attr "pool_range" "*,*,*,1020,*")
+   (set_attr "neg_pool_range" "*,*,*,1008,*")]
+)
+
+(define_split
+  [(set (match_operand:ANY64 0 "arm_general_register_operand" "")
+       (match_operand:ANY64 1 "const_double_operand" ""))]
+  "TARGET_ARM
+   && reload_completed
+   && (arm_const_double_inline_cost (operands[1])
+       <= ((optimize_size || arm_ld_sched) ? 3 : 4))"
+  [(const_int 0)]
+  "
+  arm_split_constant (SET, SImode, curr_insn,
+                     INTVAL (gen_lowpart (SImode, operands[1])),
+                     gen_lowpart (SImode, operands[0]), NULL_RTX, 0);
+  arm_split_constant (SET, SImode, curr_insn,
+                     INTVAL (gen_highpart_mode (SImode,
+                                                GET_MODE (operands[0]),
+                                                operands[1])),
+                     gen_highpart (SImode, operands[0]), NULL_RTX, 0);
+  DONE;
+  "
+)
+
+; If optimizing for size, or if we have load delay slots, then 
+; we want to split the constant into two separate operations. 
+; In both cases this may split a trivial part into a single data op
+; leaving a single complex constant to load.  We can also get longer
+; offsets in a LDR which means we get better chances of sharing the pool
+; entries.  Finally, we can normally do a better job of scheduling
+; LDR instructions than we can with LDM.
+; This pattern will only match if the one above did not.
+(define_split
+  [(set (match_operand:ANY64 0 "arm_general_register_operand" "")
+       (match_operand:ANY64 1 "const_double_operand" ""))]
+  "TARGET_ARM && reload_completed
+   && arm_const_double_by_parts (operands[1])"
+  [(set (match_dup 0) (match_dup 1))
+   (set (match_dup 2) (match_dup 3))]
+  "
+  operands[2] = gen_highpart (SImode, operands[0]);
+  operands[3] = gen_highpart_mode (SImode, GET_MODE (operands[0]),
+                                  operands[1]);
+  operands[0] = gen_lowpart (SImode, operands[0]);
+  operands[1] = gen_lowpart (SImode, operands[1]);
+  "
+)
+
+(define_split
+  [(set (match_operand:ANY64 0 "arm_general_register_operand" "")
+       (match_operand:ANY64 1 "arm_general_register_operand" ""))]
+  "TARGET_EITHER && reload_completed"
+  [(set (match_dup 0) (match_dup 1))
+   (set (match_dup 2) (match_dup 3))]
+  "
+  operands[2] = gen_highpart (SImode, operands[0]);
+  operands[3] = gen_highpart (SImode, operands[1]);
+  operands[0] = gen_lowpart (SImode, operands[0]);
+  operands[1] = gen_lowpart (SImode, operands[1]);
+
+  /* Handle a partial overlap.  */
+  if (rtx_equal_p (operands[0], operands[3]))
+    {
+      rtx tmp0 = operands[0];
+      rtx tmp1 = operands[1];
+
+      operands[0] = operands[2];
+      operands[1] = operands[3];
+      operands[2] = tmp0;
+      operands[3] = tmp1;
+    }
+  "
+)
+
+;; We can't actually do base+index doubleword loads if the index and
+;; destination overlap.  Split here so that we at least have chance to
+;; schedule.
+(define_split
+  [(set (match_operand:DI 0 "s_register_operand" "")
+       (mem:DI (plus:SI (match_operand:SI 1 "s_register_operand" "")
+                        (match_operand:SI 2 "s_register_operand" ""))))]
+  "TARGET_LDRD
+  && reg_overlap_mentioned_p (operands[0], operands[1])
+  && reg_overlap_mentioned_p (operands[0], operands[2])"
+  [(set (match_dup 4)
+       (plus:SI (match_dup 1)
+                (match_dup 2)))
+   (set (match_dup 0)
+       (mem:DI (match_dup 4)))]
+  "
+  operands[4] = gen_rtx_REG (SImode, REGNO(operands[0]));
   "
-  [(set_attr "length" "8")
-   (set_attr "type" "*,load,store2")
-   (set_attr "pool_range" "*,1020,*")
-   (set_attr "neg_pool_range" "*,1008,*")]
 )
 
 ;;; ??? This should have alternatives for constants.
   [(set (match_operand:DI 0 "nonimmediate_operand" "=l,l,l,l,>,l, m,*r")
        (match_operand:DI 1 "general_operand"      "l, I,J,>,l,mi,l,*r"))]
   "TARGET_THUMB
-   && !TARGET_CIRRUS
+   && !(TARGET_HARD_FLOAT && TARGET_MAVERICK)
    && (   register_operand (operands[0], DImode)
        || register_operand (operands[1], DImode))"
   "*
     case 5:
       return thumb_load_double_from_address (operands);
     case 6:
-      operands[2] = gen_rtx (MEM, SImode,
+      operands[2] = gen_rtx_MEM (SImode,
                             plus_constant (XEXP (operands[0], 0), 4));
       output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands);
       return \"\";
     }
   }"
   [(set_attr "length" "4,4,6,2,2,6,4,4")
-   (set_attr "type" "*,*,*,load,store2,load,store2,*")
+   (set_attr "type" "*,*,*,load2,store2,load2,store2,*")
    (set_attr "pool_range" "*,*,*,*,*,1020,*,*")]
 )
 
   "
   if (TARGET_ARM)
     {
-      /* Everything except mem = const or mem = mem can be done easily */
+      /* Everything except mem = const or mem = mem can be done easily */
       if (GET_CODE (operands[0]) == MEM)
         operands[1] = force_reg (SImode, operands[1]);
-      if (GET_CODE (operands[1]) == CONST_INT
+      if (arm_general_register_operand (operands[0], SImode)
+         && GET_CODE (operands[1]) == CONST_INT
           && !(const_ok_for_arm (INTVAL (operands[1]))
                || const_ok_for_arm (~INTVAL (operands[1]))))
         {
-           arm_split_constant (SET, SImode, INTVAL (operands[1]), operands[0],
-                             NULL_RTX,
-                             (no_new_pseudos ? 0
-                              : preserve_subexpressions_p ()));
+           arm_split_constant (SET, SImode, NULL_RTX,
+                              INTVAL (operands[1]), operands[0], NULL_RTX,
+                              optimize && !no_new_pseudos);
           DONE;
         }
     }
-  else /* TARGET_THUMB.... */
+  else /* TARGET_THUMB....  */
     {
       if (!no_new_pseudos)
         {
 (define_insn "*arm_movsi_insn"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r, m")
        (match_operand:SI 1 "general_operand"      "rI,K,mi,r"))]
-  "TARGET_ARM
+  "TARGET_ARM && ! TARGET_IWMMXT
+   && !(TARGET_HARD_FLOAT && TARGET_VFP)
    && (   register_operand (operands[0], SImode)
        || register_operand (operands[1], SImode))"
   "@
    mvn%?\\t%0, #%B1
    ldr%?\\t%0, %1
    str%?\\t%1, %0"
-  [(set_attr "type" "*,*,load,store1")
+  [(set_attr "type" "*,*,load1,store1")
    (set_attr "predicable" "yes")
    (set_attr "pool_range" "*,*,4096,*")
    (set_attr "neg_pool_range" "*,*,4084,*")]
 )
 
 (define_split
-  [(set (match_operand:SI 0 "s_register_operand" "")
+  [(set (match_operand:SI 0 "arm_general_register_operand" "")
        (match_operand:SI 1 "const_int_operand" ""))]
   "TARGET_ARM
   && (!(const_ok_for_arm (INTVAL (operands[1]))
         || const_ok_for_arm (~INTVAL (operands[1]))))"
   [(clobber (const_int 0))]
   "
-  arm_split_constant (SET, SImode, INTVAL (operands[1]), operands[0],
-                     NULL_RTX, 0);
+  arm_split_constant (SET, SImode, NULL_RTX, 
+                      INTVAL (operands[1]), operands[0], NULL_RTX, 0);
   DONE;
   "
 )
    str\\t%1, %0
    mov\\t%0, %1"
   [(set_attr "length" "2,2,4,4,2,2,2,2,2")
-   (set_attr "type" "*,*,*,*,load,store1,load,store1,*")
+   (set_attr "type" "*,*,*,*,load1,store1,load1,store1,*")
    (set_attr "pool_range" "*,*,*,*,*,*,1020,*,*")]
 )
 
        (unspec:SI [(match_operand:SI 1 "" "mX")] UNSPEC_PIC_SYM))]
   "TARGET_ARM && flag_pic"
   "ldr%?\\t%0, %1"
-  [(set_attr "type" "load")
+  [(set_attr "type" "load1")
    (set (attr "pool_range")     (const_int 4096))
    (set (attr "neg_pool_range") (const_int 4084))]
 )
        (unspec:SI [(match_operand:SI 1 "" "mX")] UNSPEC_PIC_SYM))]
   "TARGET_THUMB && flag_pic"
   "ldr\\t%0, %1"
-  [(set_attr "type" "load")
+  [(set_attr "type" "load1")
    (set (attr "pool_range") (const_int 1024))]
 )
 
 ;; This variant is used for AOF assembly, since it needs to mention the
 ;; pic register in the rtl.
 (define_expand "pic_load_addr_based"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+  [(set (match_operand:SI 0 "s_register_operand" "")
        (unspec:SI [(match_operand 1 "" "") (match_dup 2)] UNSPEC_PIC_SYM))]
   "TARGET_ARM && flag_pic"
   "operands[2] = pic_offset_table_rtx;"
   output_asm_insn (\"ldr%?\\t%0, %a1\", operands);
   return \"\";
   "
-  [(set_attr "type" "load")
+  [(set_attr "type" "load1")
    (set (attr "pool_range")
        (if_then_else (eq_attr "is_thumb" "yes")
                      (const_int 1024)
 
 (define_insn "pic_add_dot_plus_four"
   [(set (match_operand:SI 0 "register_operand" "+r")
-       (plus:SI (match_dup 0) (const (plus:SI (pc) (const_int 4)))))
+       (unspec:SI [(plus:SI (match_dup 0)
+                            (const (plus:SI (pc) (const_int 4))))]
+                  UNSPEC_PIC_BASE))
    (use (label_ref (match_operand 1 "" "")))]
   "TARGET_THUMB && flag_pic"
   "*
 
 (define_insn "pic_add_dot_plus_eight"
   [(set (match_operand:SI 0 "register_operand" "+r")
-       (plus:SI (match_dup 0) (const (plus:SI (pc) (const_int 8)))))
+       (unspec:SI [(plus:SI (match_dup 0)
+                            (const (plus:SI (pc) (const_int 8))))]
+                  UNSPEC_PIC_BASE))
    (use (label_ref (match_operand 1 "" "")))]
   "TARGET_ARM && flag_pic"
   "*
   "flag_pic"
   "
 {
-  arm_finalize_pic (0);
+  /* r3 is clobbered by set/longjmp, so we can use it as a scratch
+     register.  */
+  arm_load_pic_register (3);
   DONE;
 }")
 
    (set (match_dup 2)
        (ashiftrt:SI (match_operand 0 "" "") (const_int 8)))
    ;; store the high byte
-   (set (match_dup 4) (subreg:QI (match_dup 2) 0))]    ;explicit subreg safe
+   (set (match_dup 4) (match_dup 5))]
   "TARGET_ARM"
   "
   {
     operands[1] = adjust_address (operands[1], QImode, 0);
     operands[3] = gen_lowpart (QImode, operands[0]);
     operands[0] = gen_lowpart (SImode, operands[0]);
-    operands[2] = gen_reg_rtx (SImode); 
+    operands[2] = gen_reg_rtx (SImode);
+    operands[5] = gen_lowpart (QImode, operands[2]);
   }"
 )
 
   [(set (match_dup 4) (match_dup 3))
    (set (match_dup 2)
        (ashiftrt:SI (match_operand 0 "" "") (const_int 8)))
-   (set (match_operand 1 "" "")        (subreg:QI (match_dup 2) 3))]
+   (set (match_operand 1 "" "")        (match_dup 5))]
   "TARGET_ARM"
   "
   {
     operands[3] = gen_lowpart (QImode, operands[0]);
     operands[0] = gen_lowpart (SImode, operands[0]);
     operands[2] = gen_reg_rtx (SImode);
+    operands[5] = gen_lowpart (QImode, operands[2]);
   }"
 )
 
 ;; Subroutine to store a half word integer constant into memory.
 (define_expand "storeinthi"
   [(set (match_operand 0 "" "")
-       (subreg:QI (match_operand 1 "" "") 0))
+       (match_operand 1 "" ""))
    (set (match_dup 3) (match_dup 2))]
   "TARGET_ARM"
   "
     operands[3] = adjust_address (op0, QImode, 1);
     operands[0] = adjust_address (operands[0], QImode, 0);
     operands[2] = gen_lowpart (QImode, operands[2]);
+    operands[1] = gen_lowpart (QImode, operands[1]);
   }"
 )
 
              emit_insn (gen_movsi (reg, GEN_INT (val)));
              operands[1] = gen_lowpart (HImode, reg);
            }
-         else if (arm_arch4 && !no_new_pseudos && optimize > 0
+         else if (arm_arch4 && optimize && !no_new_pseudos
                   && GET_CODE (operands[1]) == MEM)
            {
              rtx reg = gen_reg_rtx (SImode);
            }
           else if (!arm_arch4)
            {
-            /* Note: We do not have to worry about TARGET_MMU_TRAPS
-               for v4 and up architectures because LDRH instructions will
-               be used to access the HI values, and these cannot generate
-               unaligned word access faults in the MMU.  */
              if (GET_CODE (operands[1]) == MEM)
                {
-                 if (TARGET_MMU_TRAPS)
-                   {
-                     rtx base;
-                     rtx offset = const0_rtx;
-                     rtx reg = gen_reg_rtx (SImode);
-
-                     if ((GET_CODE (base = XEXP (operands[1], 0)) == REG
-                          || (GET_CODE (base) == PLUS
-                              && (GET_CODE (offset = XEXP (base, 1))
-                                  == CONST_INT)
-                               && ((INTVAL(offset) & 1) != 1)
-                              && GET_CODE (base = XEXP (base, 0)) == REG))
-                         && REGNO_POINTER_ALIGN (REGNO (base)) >= 32)
-                       {
-                         HOST_WIDE_INT new_offset = INTVAL (offset) & ~3;
-                         rtx new;
-
-                         new = gen_rtx_MEM (SImode,
-                                            plus_constant (base, new_offset));
-                         MEM_COPY_ATTRIBUTES (new, operands[1]);
-                         emit_insn (gen_movsi (reg, new));
-                         if (((INTVAL (offset) & 2) != 0)
-                             ^ (BYTES_BIG_ENDIAN ? 1 : 0))
-                           {
-                             rtx reg2 = gen_reg_rtx (SImode);
-
-                             emit_insn (gen_lshrsi3 (reg2, reg,
-                                        GEN_INT (16)));
-                             reg = reg2;
-                           }
-                       }
-                     else
-                       emit_insn (gen_movhi_bytes (reg, operands[1]));
-
-                     operands[1] = gen_lowpart (HImode, reg);
-                   }
-                 else if (BYTES_BIG_ENDIAN)
+                 rtx base;
+                 rtx offset = const0_rtx;
+                 rtx reg = gen_reg_rtx (SImode);
+
+                 if ((GET_CODE (base = XEXP (operands[1], 0)) == REG
+                      || (GET_CODE (base) == PLUS
+                          && (GET_CODE (offset = XEXP (base, 1))
+                              == CONST_INT)
+                           && ((INTVAL(offset) & 1) != 1)
+                          && GET_CODE (base = XEXP (base, 0)) == REG))
+                     && REGNO_POINTER_ALIGN (REGNO (base)) >= 32)
                    {
-                     rtx base;
-                     rtx offset = const0_rtx;
-
-                     if ((GET_CODE (base = XEXP (operands[1], 0)) == REG
-                          || (GET_CODE (base) == PLUS
-                             && (GET_CODE (offset = XEXP (base, 1))
-                                 == CONST_INT)
-                             && GET_CODE (base = XEXP (base, 0)) == REG))
-                         && REGNO_POINTER_ALIGN (REGNO (base)) >= 32)
-                       {
-                         rtx reg = gen_reg_rtx (SImode);
-                         rtx new;
-
-                         if ((INTVAL (offset) & 2) == 2)
-                           {
-                             HOST_WIDE_INT new_offset = INTVAL (offset) ^ 2;
-                             new = gen_rtx_MEM (SImode,
-                                                plus_constant (base,
-                                                               new_offset));
-                              MEM_COPY_ATTRIBUTES (new, operands[1]);
-                             emit_insn (gen_movsi (reg, new));
-                           }
-                         else
-                           {
-                             new = gen_rtx_MEM (SImode,
-                                                XEXP (operands[1], 0));
-                             MEM_COPY_ATTRIBUTES (new, operands[1]);
-                             emit_insn (gen_rotated_loadsi (reg, new));
-                           }
-
-                         operands[1] = gen_lowpart (HImode, reg);
-                       }
-                     else
-                       {
-                         emit_insn (gen_movhi_bigend (operands[0],
-                                                      operands[1]));
-                         DONE;
-                       }
+                     rtx new;
+
+                     new = widen_memory_access (operands[1], SImode,
+                                                ((INTVAL (offset) & ~3)
+                                                 - INTVAL (offset)));
+                     emit_insn (gen_movsi (reg, new));
+                     if (((INTVAL (offset) & 2) != 0)
+                         ^ (BYTES_BIG_ENDIAN ? 1 : 0))
+                       {
+                         rtx reg2 = gen_reg_rtx (SImode);
+
+                         emit_insn (gen_lshrsi3 (reg2, reg, GEN_INT (16)));
+                         reg = reg2;
+                       }
                    }
+                 else
+                   emit_insn (gen_movhi_bytes (reg, operands[1]));
+
+                 operands[1] = gen_lowpart (HImode, reg);
               }
           }
         }
-      /* Handle loading a large integer during reload */
+      /* Handle loading a large integer during reload */
       else if (GET_CODE (operands[1]) == CONST_INT
               && !const_ok_for_arm (INTVAL (operands[1]))
               && !const_ok_for_arm (~INTVAL (operands[1])))
         {
           /* Writing a constant to memory needs a scratch, which should
             be handled with SECONDARY_RELOADs.  */
-          if (GET_CODE (operands[0]) != REG)
-           abort ();
+          gcc_assert (GET_CODE (operands[0]) == REG);
 
           operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0);
           emit_insn (gen_movsi (operands[0], operands[1]));
     {
       if (!no_new_pseudos)
         {
-          if (GET_CODE (operands[0]) != REG)
-           operands[1] = force_reg (HImode, operands[1]);
+         if (GET_CODE (operands[1]) == CONST_INT)
+           {
+             rtx reg = gen_reg_rtx (SImode);
+
+             emit_insn (gen_movsi (reg, operands[1]));
+             operands[1] = gen_lowpart (HImode, reg);
+           }
 
           /* ??? We shouldn't really get invalid addresses here, but this can
             happen if we are passed a SP (never OK for HImode/QImode) or 
            operands[1]
              = replace_equiv_address (operands[1],
                                       copy_to_reg (XEXP (operands[1], 0)));
+
+         if (GET_CODE (operands[1]) == MEM && optimize > 0)
+           {
+             rtx reg = gen_reg_rtx (SImode);
+
+             emit_insn (gen_zero_extendhisi2 (reg, operands[1]));
+             operands[1] = gen_lowpart (HImode, reg);
+           }
+
+          if (GET_CODE (operands[0]) == MEM)
+           operands[1] = force_reg (HImode, operands[1]);
         }
-      /* Handle loading a large integer during reload */
       else if (GET_CODE (operands[1]) == CONST_INT
                && !CONST_OK_FOR_THUMB_LETTER (INTVAL (operands[1]), 'I'))
         {
+         /* Handle loading a large integer during reload.  */
+
           /* Writing a constant to memory needs a scratch, which should
             be handled with SECONDARY_RELOADs.  */
-          if (GET_CODE (operands[0]) != REG)
-           abort ();
+          gcc_assert (GET_CODE (operands[0]) == REG);
 
-          operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0);
+          operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0);
           emit_insn (gen_movsi (operands[0], operands[1]));
           DONE;
         }
 )
 
 (define_insn "*thumb_movhi_insn"
-  [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l, m,*r,*h,l")
-       (match_operand:HI 1 "general_operand"       "l,mn,l,*h,*r,I"))]
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l")
+       (match_operand:HI 1 "general_operand"       "l,m,l,*h,*r,I"))]
   "TARGET_THUMB
    && (   register_operand (operands[0], HImode)
        || register_operand (operands[1], HImode))"
     case 3: return \"mov       %0, %1\";
     case 4: return \"mov       %0, %1\";
     case 5: return \"mov       %0, %1\";
-    default: abort ();
+    default: gcc_unreachable ();
     case 1:
       /* The stack pointer can end up being taken as an index register.
           Catch this case here and deal with it.  */
       return \"ldrh    %0, %1\";
     }"
   [(set_attr "length" "2,4,2,2,2,2")
-   (set_attr "type" "*,load,store1,*,*,*")
-   (set_attr "pool_range" "*,64,*,*,*,*")]
+   (set_attr "type" "*,load1,store1,*,*,*")]
 )
 
 
-(define_insn "rotated_loadsi"
-  [(set (match_operand:SI            0 "s_register_operand"        "=r")
-       (rotate:SI (match_operand:SI 1 "offsettable_memory_operand" "o")
-                  (const_int 16)))]
-  "TARGET_ARM && (!TARGET_MMU_TRAPS)"
-  "*
-  {
-    rtx ops[2];
-
-    ops[0] = operands[0];
-    ops[1] = gen_rtx_MEM (SImode, plus_constant (XEXP (operands[1], 0), 2));
-    output_asm_insn (\"ldr%?\\t%0, %1\\t%@ load-rotate\", ops);
-    return \"\";
-  }"
-  [(set_attr "type" "load")
-   (set_attr "predicable" "yes")]
-)
-
 (define_expand "movhi_bytes"
   [(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" "")))
    (set (match_dup 3)
     rtx mem1, mem2;
     rtx addr = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
 
-    mem1 = gen_rtx_MEM (QImode, addr);
-    MEM_COPY_ATTRIBUTES (mem1, operands[1]);
-    mem2 = gen_rtx_MEM (QImode, plus_constant (addr, 1));
-    MEM_COPY_ATTRIBUTES (mem2, operands[1]);
+    mem1 = change_address (operands[1], QImode, addr);
+    mem2 = change_address (operands[1], QImode, plus_constant (addr, 1));
     operands[0] = gen_lowpart (SImode, operands[0]);
     operands[1] = mem1;
     operands[2] = gen_reg_rtx (SImode);
    (set (match_dup 3)
        (ashiftrt:SI (match_dup 2) (const_int 16)))
    (set (match_operand:HI 0 "s_register_operand" "")
-       (subreg:HI (match_dup 3) 0))]
+       (match_dup 4))]
   "TARGET_ARM"
   "
   operands[2] = gen_reg_rtx (SImode);
   operands[3] = gen_reg_rtx (SImode);
+  operands[4] = gen_lowpart (HImode, operands[3]);
   "
 )
 
   "@
    mov%?\\t%0, %1\\t%@ movhi
    mvn%?\\t%0, #%B1\\t%@ movhi
-   str%?h\\t%1, %0\\t%@ movhi 
+   str%?h\\t%1, %0\\t%@ movhi
    ldr%?h\\t%0, %1\\t%@ movhi"
-  [(set_attr "type" "*,*,store1,load")
+  [(set_attr "type" "*,*,store1,load1")
    (set_attr "predicable" "yes")
    (set_attr "pool_range" "*,*,*,256")
    (set_attr "neg_pool_range" "*,*,*,244")]
 )
 
-(define_insn "*movhi_insn_littleend"
-  [(set (match_operand:HI 0 "s_register_operand" "=r,r,r")
-       (match_operand:HI 1 "general_operand"  "rI,K,m"))]
-  "TARGET_ARM
-   && !arm_arch4
-   && !BYTES_BIG_ENDIAN
-   && !TARGET_MMU_TRAPS
-   && (GET_CODE (operands[1]) != CONST_INT
-       || const_ok_for_arm (INTVAL (operands[1]))
-       || const_ok_for_arm (~INTVAL (operands[1])))"
-  "@
-   mov%?\\t%0, %1\\t%@ movhi
-   mvn%?\\t%0, #%B1\\t%@ movhi
-   ldr%?\\t%0, %1\\t%@ movhi"
-  [(set_attr "type" "*,*,load")
-   (set_attr "predicable" "yes")
-   (set_attr "pool_range" "4096")
-   (set_attr "neg_pool_range" "4084")]
-)
-
-(define_insn "*movhi_insn_bigend"
-  [(set (match_operand:HI 0 "s_register_operand" "=r,r,r")
-       (match_operand:HI 1 "general_operand"    "rI,K,m"))]
-  "TARGET_ARM
-   && !arm_arch4
-   && BYTES_BIG_ENDIAN
-   && !TARGET_MMU_TRAPS
-   && (GET_CODE (operands[1]) != CONST_INT
-       || const_ok_for_arm (INTVAL (operands[1]))
-       || const_ok_for_arm (~INTVAL (operands[1])))"
-  "@
-   mov%?\\t%0, %1\\t%@ movhi
-   mvn%?\\t%0, #%B1\\t%@ movhi
-   ldr%?\\t%0, %1\\t%@ movhi_bigend\;mov%?\\t%0, %0, asr #16"
-  [(set_attr "type" "*,*,load")
-   (set_attr "predicable" "yes")
-   (set_attr "length" "4,4,8")
-   (set_attr "pool_range" "*,*,4092")
-   (set_attr "neg_pool_range" "*,*,4084")]
-)
-
-(define_insn "*loadhi_si_bigend"
-  [(set (match_operand:SI                       0 "s_register_operand" "=r")
-       (rotate:SI (subreg:SI (match_operand:HI 1 "memory_operand"      "m") 0)
-                  (const_int 16)))]
-  "TARGET_ARM
-   && BYTES_BIG_ENDIAN
-   && !TARGET_MMU_TRAPS"
-  "ldr%?\\t%0, %1\\t%@ movhi_bigend"
-  [(set_attr "type" "load")
-   (set_attr "predicable" "yes")
-   (set_attr "pool_range" "4096")
-   (set_attr "neg_pool_range" "4084")]
-)
-
 (define_insn "*movhi_bytes"
   [(set (match_operand:HI 0 "s_register_operand" "=r,r")
        (match_operand:HI 1 "arm_rhs_operand"  "rI,K"))]
-  "TARGET_ARM && TARGET_MMU_TRAPS"
+  "TARGET_ARM"
   "@
    mov%?\\t%0, %1\\t%@ movhi
    mvn%?\\t%0, #%B1\\t%@ movhi"
   [(set_attr "predicable" "yes")]
 )
 
-(define_insn "thumb_movhi_clobber"
-  [(set (match_operand:HI     0 "memory_operand"   "=m")
-       (match_operand:HI     1 "register_operand" "l"))
-   (clobber (match_operand:SI 2 "register_operand" "=&l"))]
+(define_expand "thumb_movhi_clobber"
+  [(set (match_operand:HI     0 "memory_operand"   "")
+       (match_operand:HI     1 "register_operand" ""))
+   (clobber (match_operand:DI 2 "register_operand" ""))]
   "TARGET_THUMB"
-  "*
-  abort ();"
+  "
+  if (strict_memory_address_p (HImode, XEXP (operands[0], 0))
+      && REGNO (operands[1]) <= LAST_LO_REGNUM)
+    {
+      emit_insn (gen_movhi (operands[0], operands[1]));
+      DONE;
+    }
+  /* XXX Fixme, need to handle other cases here as well.  */
+  gcc_unreachable ();
+  "
 )
        
 ;; We use a DImode scratch because we may occasionally need an additional
   [(parallel [(match_operand:HI 0 "s_register_operand" "=r")
              (match_operand:HI 1 "arm_reload_memory_operand" "o")
              (match_operand:DI 2 "s_register_operand" "=&r")])]
-  "TARGET_THUMB || (TARGET_ARM && TARGET_MMU_TRAPS)"
+  "TARGET_EITHER"
   "
   if (TARGET_ARM)
     arm_reload_in_hi (operands);
         (match_operand:QI 1 "general_operand" ""))]
   "TARGET_EITHER"
   "
-  if (TARGET_ARM)
-    {
-      /* Everything except mem = const or mem = mem can be done easily */
-
-      if (!no_new_pseudos)
-        {
-          if (GET_CODE (operands[1]) == CONST_INT)
-           {
-             rtx reg = gen_reg_rtx (SImode);
-
-             emit_insn (gen_movsi (reg, operands[1]));
-             operands[1] = gen_lowpart (QImode, reg);
-           }
-         if (GET_CODE (operands[1]) == MEM && optimize > 0)
-           {
-             rtx reg = gen_reg_rtx (SImode);
+  /* Everything except mem = const or mem = mem can be done easily */
 
-             emit_insn (gen_zero_extendqisi2 (reg, operands[1]));
-             operands[1] = gen_lowpart (QImode, reg);
-           }
-          if (GET_CODE (operands[0]) == MEM)
-           operands[1] = force_reg (QImode, operands[1]);
-        }
-    }
-  else /* TARGET_THUMB */
+  if (!no_new_pseudos)
     {
-      if (!no_new_pseudos)
-        {
-          if (GET_CODE (operands[0]) != REG)
-           operands[1] = force_reg (QImode, operands[1]);
+      if (GET_CODE (operands[1]) == CONST_INT)
+       {
+         rtx reg = gen_reg_rtx (SImode);
+
+         emit_insn (gen_movsi (reg, operands[1]));
+         operands[1] = gen_lowpart (QImode, reg);
+       }
 
+      if (TARGET_THUMB)
+       {
           /* ??? We shouldn't really get invalid addresses here, but this can
             happen if we are passed a SP (never OK for HImode/QImode) or
             virtual register (rejected by GO_IF_LEGITIMATE_ADDRESS for
             operands[1]
               = replace_equiv_address (operands[1],
                                        copy_to_reg (XEXP (operands[1], 0)));
-        }
-      /* Handle loading a large integer during reload */
-      else if (GET_CODE (operands[1]) == CONST_INT
-              && !CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I'))
-        {
-          /* Writing a constant to memory needs a scratch, which should
-            be handled with SECONDARY_RELOADs.  */
-          if (GET_CODE (operands[0]) != REG)
-           abort ();
+       }
 
-          operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0);
-          emit_insn (gen_movsi (operands[0], operands[1]));
-          DONE;
-       }
+      if (GET_CODE (operands[1]) == MEM && optimize > 0)
+       {
+         rtx reg = gen_reg_rtx (SImode);
+
+         emit_insn (gen_zero_extendqisi2 (reg, operands[1]));
+         operands[1] = gen_lowpart (QImode, reg);
+       }
+
+      if (GET_CODE (operands[0]) == MEM)
+       operands[1] = force_reg (QImode, operands[1]);
+    }
+  else if (TARGET_THUMB
+          && GET_CODE (operands[1]) == CONST_INT
+          && !CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I'))
+    {
+      /* Handle loading a large integer during reload.  */
+
+      /* Writing a constant to memory needs a scratch, which should
+        be handled with SECONDARY_RELOADs.  */
+      gcc_assert (GET_CODE (operands[0]) == REG);
+
+      operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0);
+      emit_insn (gen_movsi (operands[0], operands[1]));
+      DONE;
     }
   "
 )
    mvn%?\\t%0, #%B1
    ldr%?b\\t%0, %1
    str%?b\\t%1, %0"
-  [(set_attr "type" "*,*,load,store1")
+  [(set_attr "type" "*,*,load1,store1")
    (set_attr "predicable" "yes")]
 )
 
    mov\\t%0, %1
    mov\\t%0, %1"
   [(set_attr "length" "2")
-   (set_attr "type" "*,load,store1,*,*,*")
+   (set_attr "type" "*,load1,store1,*,*,*")
    (set_attr "pool_range" "*,32,*,*,*,*")]
 )
 
   [(set (match_operand:SF 0 "nonimmediate_operand" "")
        (match_operand:SF 1 "immediate_operand" ""))]
   "TARGET_ARM
-   && !TARGET_HARD_FLOAT
+   && !(TARGET_HARD_FLOAT && TARGET_FPA)
    && reload_completed
    && GET_CODE (operands[1]) == CONST_DOUBLE"
   [(set (match_dup 2) (match_dup 3))]
   "
 )
 
-(define_insn "*arm_movsf_hard_insn"
-  [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f, m,f,r,r,r, m")
-       (match_operand:SF 1 "general_operand"      "fG,H,mE,f,r,f,r,mE,r"))]
+(define_insn "*arm_movsf_soft_insn"
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m")
+       (match_operand:SF 1 "general_operand"  "r,mE,r"))]
   "TARGET_ARM
-   && TARGET_HARD_FLOAT
+   && TARGET_SOFT_FLOAT
    && (GET_CODE (operands[0]) != MEM
        || register_operand (operands[1], SFmode))"
   "@
-   mvf%?s\\t%0, %1
-   mnf%?s\\t%0, #%N1
-   ldf%?s\\t%0, %1
-   stf%?s\\t%1, %0
-   str%?\\t%1, [%|sp, #-4]!\;ldf%?s\\t%0, [%|sp], #4
-   stf%?s\\t%1, [%|sp, #-4]!\;ldr%?\\t%0, [%|sp], #4
    mov%?\\t%0, %1
    ldr%?\\t%0, %1\\t%@ float
    str%?\\t%1, %0\\t%@ float"
-  [(set_attr "length" "4,4,4,4,8,8,4,4,4")
+  [(set_attr "length" "4,4,4")
    (set_attr "predicable" "yes")
-   (set_attr "type"
-        "ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r,*,load,store1")
-   (set_attr "pool_range" "*,*,1024,*,*,*,*,4096,*")
-   (set_attr "neg_pool_range" "*,*,1012,*,*,*,*,4084,*")]
-)
-
-;; Exactly the same as above, except that all `f' cases are deleted.
-;; This is necessary to prevent reload from ever trying to use a `f' reg
-;; when -msoft-float.
-
-(define_insn "*arm_movsf_soft_insn"
-  [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m")
-       (match_operand:SF 1 "general_operand"  "r,mE,r"))]
-  "TARGET_ARM
-   && !TARGET_CIRRUS
-   && TARGET_SOFT_FLOAT
-   && (GET_CODE (operands[0]) != MEM
-       || register_operand (operands[1], SFmode))"
-  "@
-   mov%?\\t%0, %1
-   ldr%?\\t%0, %1\\t%@ float
-   str%?\\t%1, %0\\t%@ float"
-  [(set_attr "length" "4,4,4")
-   (set_attr "predicable" "yes")
-   (set_attr "type" "*,load,store1")
-   (set_attr "pool_range" "*,4096,*")
-   (set_attr "neg_pool_range" "*,4084,*")]
+   (set_attr "type" "*,load1,store1")
+   (set_attr "pool_range" "*,4096,*")
+   (set_attr "neg_pool_range" "*,4084,*")]
 )
 
 ;;; ??? This should have alternatives for constants.
    mov\\t%0, %1
    mov\\t%0, %1"
   [(set_attr "length" "2")
-   (set_attr "type" "*,load,store1,load,store1,*,*")
+   (set_attr "type" "*,load1,store1,load1,store1,*,*")
    (set_attr "pool_range" "*,*,*,1020,*,*,*")]
 )
 
       emit_insn (gen_addsi3 (operands[2], XEXP (XEXP (operands[0], 0), 0),
                             XEXP (XEXP (operands[0], 0), 1)));
 
-    emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_MEM (DFmode, operands[2]),
+    emit_insn (gen_rtx_SET (VOIDmode,
+                           replace_equiv_address (operands[0], operands[2]),
                            operands[1]));
 
     if (code == POST_DEC)
   }"
 )
 
-(define_insn "*movdf_hard_insn"
-  [(set (match_operand:DF 0 "nonimmediate_operand"
-                                               "=r,Q,r,m,r, f, f,f, m,!f,!r")
-       (match_operand:DF 1 "general_operand"
-                                               "Q, r,r,r,mF,fG,H,mF,f,r, f"))]
-  "TARGET_ARM
-   && TARGET_HARD_FLOAT
-   && (GET_CODE (operands[0]) != MEM
-       || register_operand (operands[1], DFmode))"
+(define_insn "*movdf_soft_insn"
+  [(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=r,r,r,r,m")
+       (match_operand:DF 1 "soft_df_operand" "rDa,Db,Dc,mF,r"))]
+  "TARGET_ARM && TARGET_SOFT_FLOAT
+  "
   "*
-  {
   switch (which_alternative)
     {
+    case 0:
+    case 1:
+    case 2:
+      return \"#\";
     default:
-    case 0: return \"ldm%?ia\\t%m1, %M0\\t%@ double\";
-    case 1: return \"stm%?ia\\t%m0, %M1\\t%@ double\";
-    case 2: case 3: case 4: return output_move_double (operands);
-    case 5: return \"mvf%?d\\t%0, %1\";
-    case 6: return \"mnf%?d\\t%0, #%N1\";
-    case 7: return \"ldf%?d\\t%0, %1\";
-    case 8: return \"stf%?d\\t%1, %0\";
-    case 9: return output_mov_double_fpu_from_arm (operands);
-    case 10: return output_mov_double_arm_from_fpu (operands);
+      return output_move_double (operands);
     }
-  }
-  "
-  [(set_attr "length" "4,4,8,8,8,4,4,4,4,8,8")
-   (set_attr "predicable" "yes")
-   (set_attr "type"
-    "load,store2,*,store2,load,ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r")
-   (set_attr "pool_range" "*,*,*,*,1020,*,*,1024,*,*,*")
-   (set_attr "neg_pool_range" "*,*,*,*,1008,*,*,1008,*,*,*")]
-)
-
-;; Software floating point version.  This is essentially the same as movdi.
-;; Do not use `f' as a constraint to prevent reload from ever trying to use
-;; an `f' reg.
-
-(define_insn "*movdf_soft_insn"
-  [(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=r,r,m")
-       (match_operand:DF 1 "soft_df_operand" "r,mF,r"))]
-  "TARGET_ARM && TARGET_SOFT_FLOAT
-   && !TARGET_CIRRUS
   "
-  "* return output_move_double (operands);"
-  [(set_attr "length" "8,8,8")
-   (set_attr "type" "*,load,store2")
+  [(set_attr "length" "8,12,16,8,8")
+   (set_attr "type" "*,*,*,load2,store2")
    (set_attr "pool_range" "1020")
    (set_attr "neg_pool_range" "1008")]
 )
     case 3:
       return thumb_load_double_from_address (operands);
     case 4:
-      operands[2] = gen_rtx (MEM, SImode,
-                            plus_constant (XEXP (operands[0], 0), 4));
+      operands[2] = gen_rtx_MEM (SImode,
+                                plus_constant (XEXP (operands[0], 0), 4));
       output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands);
       return \"\";
     case 5:
     }
   "
   [(set_attr "length" "4,2,2,6,4,4")
-   (set_attr "type" "*,load,store2,load,store2,*")
+   (set_attr "type" "*,load2,store2,load2,store2,*")
    (set_attr "pool_range" "*,*,*,1020,*,*")]
 )
 
-
-;; Saving and restoring the floating point registers in the prologue should
-;; be done in XFmode, even though we don't support that for anything else
-;; (Well, strictly it's 'internal representation', but that's effectively
-;; XFmode).
-
-(define_insn "*movxf_hard_insn"
-  [(set (match_operand:XF 0 "nonimmediate_operand" "=f,f,f,m,f,r,r")
-       (match_operand:XF 1 "general_operand" "fG,H,m,f,r,f,r"))]
-  "TARGET_ARM && TARGET_HARD_FLOAT && reload_completed"
-  "*
-  switch (which_alternative)
-    {
-    default:
-    case 0: return \"mvf%?e\\t%0, %1\";
-    case 1: return \"mnf%?e\\t%0, #%N1\";
-    case 2: return \"ldf%?e\\t%0, %1\";
-    case 3: return \"stf%?e\\t%1, %0\";
-    case 4: return output_mov_long_double_fpu_from_arm (operands);
-    case 5: return output_mov_long_double_arm_from_fpu (operands);
-    case 6: return output_mov_long_double_arm_from_arm (operands);
-    }
+(define_expand "movxf"
+  [(set (match_operand:XF 0 "general_operand" "")
+       (match_operand:XF 1 "general_operand" ""))]
+  "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
+  "
+  if (GET_CODE (operands[0]) == MEM)
+    operands[1] = force_reg (XFmode, operands[1]);
   "
-  [(set_attr "length" "4,4,4,4,8,8,12")
-   (set_attr "predicable" "yes")
-   (set_attr "type" "ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r,*")
-   (set_attr "pool_range" "*,*,1024,*,*,*,*")
-   (set_attr "neg_pool_range" "*,*,1004,*,*,*,*")]
 )
+
+;; Vector Moves
+(define_expand "movv2si"
+  [(set (match_operand:V2SI 0 "nonimmediate_operand" "")
+       (match_operand:V2SI 1 "general_operand" ""))]
+  "TARGET_REALLY_IWMMXT"
+{
+})
+
+(define_expand "movv4hi"
+  [(set (match_operand:V4HI 0 "nonimmediate_operand" "")
+       (match_operand:V4HI 1 "general_operand" ""))]
+  "TARGET_REALLY_IWMMXT"
+{
+})
+
+(define_expand "movv8qi"
+  [(set (match_operand:V8QI 0 "nonimmediate_operand" "")
+       (match_operand:V8QI 1 "general_operand" ""))]
+  "TARGET_REALLY_IWMMXT"
+{
+})
 \f
 
 ;; load- and store-multiple insns
                           (match_operand:SI 1 "" ""))
                      (use (match_operand:SI 2 "" ""))])]
   "TARGET_ARM"
-  "
+{
+  HOST_WIDE_INT offset = 0;
+
   /* Support only fixed point registers.  */
   if (GET_CODE (operands[2]) != CONST_INT
       || INTVAL (operands[2]) > 14
   operands[3]
     = arm_gen_load_multiple (REGNO (operands[0]), INTVAL (operands[2]),
                             force_reg (SImode, XEXP (operands[1], 0)),
-                            TRUE, FALSE, RTX_UNCHANGING_P(operands[1]),
-                            MEM_IN_STRUCT_P(operands[1]),
-                            MEM_SCALAR_P (operands[1]));
-  "
-)
+                            TRUE, FALSE, operands[1], &offset);
+})
 
 ;; Load multiple with write-back
 
          (mem:SI (plus:SI (match_dup 2) (const_int 12))))])]
   "TARGET_ARM && XVECLEN (operands[0], 0) == 5"
   "ldm%?ia\\t%1!, {%3, %4, %5, %6}"
-  [(set_attr "type" "load")
+  [(set_attr "type" "load4")
    (set_attr "predicable" "yes")]
 )
 
+(define_insn "*ldmsi_postinc4_thumb"
+  [(match_parallel 0 "load_multiple_operation"
+    [(set (match_operand:SI 1 "s_register_operand" "=l")
+         (plus:SI (match_operand:SI 2 "s_register_operand" "1")
+                  (const_int 16)))
+     (set (match_operand:SI 3 "arm_hard_register_operand" "")
+         (mem:SI (match_dup 2)))
+     (set (match_operand:SI 4 "arm_hard_register_operand" "")
+         (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+     (set (match_operand:SI 5 "arm_hard_register_operand" "")
+         (mem:SI (plus:SI (match_dup 2) (const_int 8))))
+     (set (match_operand:SI 6 "arm_hard_register_operand" "")
+         (mem:SI (plus:SI (match_dup 2) (const_int 12))))])]
+  "TARGET_THUMB && XVECLEN (operands[0], 0) == 5"
+  "ldmia\\t%1!, {%3, %4, %5, %6}"
+  [(set_attr "type" "load4")]
+)
+
 (define_insn "*ldmsi_postinc3"
   [(match_parallel 0 "load_multiple_operation"
     [(set (match_operand:SI 1 "s_register_operand" "=r")
          (mem:SI (plus:SI (match_dup 2) (const_int 8))))])]
   "TARGET_ARM && XVECLEN (operands[0], 0) == 4"
   "ldm%?ia\\t%1!, {%3, %4, %5}"
-  [(set_attr "type" "load")
+  [(set_attr "type" "load3")
    (set_attr "predicable" "yes")]
 )
 
          (mem:SI (plus:SI (match_dup 2) (const_int 4))))])]
   "TARGET_ARM && XVECLEN (operands[0], 0) == 3"
   "ldm%?ia\\t%1!, {%3, %4}"
-  [(set_attr "type" "load")
+  [(set_attr "type" "load2")
    (set_attr "predicable" "yes")]
 )
 
          (mem:SI (plus:SI (match_dup 1) (const_int 12))))])]
   "TARGET_ARM && XVECLEN (operands[0], 0) == 4"
   "ldm%?ia\\t%1, {%2, %3, %4, %5}"
-  [(set_attr "type" "load")
+  [(set_attr "type" "load4")
    (set_attr "predicable" "yes")]
 )
 
          (mem:SI (plus:SI (match_dup 1) (const_int 8))))])]
   "TARGET_ARM && XVECLEN (operands[0], 0) == 3"
   "ldm%?ia\\t%1, {%2, %3, %4}"
-  [(set_attr "type" "load")
+  [(set_attr "type" "load3")
    (set_attr "predicable" "yes")]
 )
 
          (mem:SI (plus:SI (match_dup 1) (const_int 4))))])]
   "TARGET_ARM && XVECLEN (operands[0], 0) == 2"
   "ldm%?ia\\t%1, {%2, %3}"
-  [(set_attr "type" "load")
+  [(set_attr "type" "load2")
    (set_attr "predicable" "yes")]
 )
 
                           (match_operand:SI 1 "" ""))
                      (use (match_operand:SI 2 "" ""))])]
   "TARGET_ARM"
-  "
-  /* Support only fixed point registers */
+{
+  HOST_WIDE_INT offset = 0;
+
+  /* Support only fixed point registers.  */
   if (GET_CODE (operands[2]) != CONST_INT
       || INTVAL (operands[2]) > 14
       || INTVAL (operands[2]) < 2
   operands[3]
     = arm_gen_store_multiple (REGNO (operands[1]), INTVAL (operands[2]),
                              force_reg (SImode, XEXP (operands[0], 0)),
-                             TRUE, FALSE, RTX_UNCHANGING_P (operands[0]),
-                             MEM_IN_STRUCT_P(operands[0]), 
-                             MEM_SCALAR_P (operands[0]));
-  "
-)
+                             TRUE, FALSE, operands[0], &offset);
+})
 
 ;; Store multiple with write-back
 
    (set_attr "type" "store4")]
 )
 
+(define_insn "*stmsi_postinc4_thumb"
+  [(match_parallel 0 "store_multiple_operation"
+    [(set (match_operand:SI 1 "s_register_operand" "=l")
+         (plus:SI (match_operand:SI 2 "s_register_operand" "1")
+                  (const_int 16)))
+     (set (mem:SI (match_dup 2))
+         (match_operand:SI 3 "arm_hard_register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
+         (match_operand:SI 4 "arm_hard_register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 2) (const_int 8)))
+         (match_operand:SI 5 "arm_hard_register_operand" ""))
+     (set (mem:SI (plus:SI (match_dup 2) (const_int 12)))
+         (match_operand:SI 6 "arm_hard_register_operand" ""))])]
+  "TARGET_THUMB && XVECLEN (operands[0], 0) == 5"
+  "stmia\\t%1!, {%3, %4, %5, %6}"
+  [(set_attr "type" "store4")]
+)
+
 (define_insn "*stmsi_postinc3"
   [(match_parallel 0 "store_multiple_operation"
     [(set (match_operand:SI 1 "s_register_operand" "=r")
 ;; We could let this apply for blocks of less than this, but it clobbers so
 ;; many registers that there is then probably a better way.
 
-(define_expand "movstrqi"
+(define_expand "movmemqi"
   [(match_operand:BLK 0 "general_operand" "")
    (match_operand:BLK 1 "general_operand" "")
    (match_operand:SI 2 "const_int_operand" "")
   "
   if (TARGET_ARM)
     {
-      if (arm_gen_movstrqi (operands))
+      if (arm_gen_movmemqi (operands))
         DONE;
       FAIL;
     }
           || INTVAL (operands[2]) > 48)
         FAIL;
 
-      thumb_expand_movstrqi (operands);
+      thumb_expand_movmemqi (operands);
       DONE;
     }
   "
 \f
 
 ;; Compare & branch insns
-;; The range calcualations are based as follows:
+;; The range calculations are based as follows:
 ;; For forward branches, the address calculation returns the address of
 ;; the next instruction.  This is 2 beyond the branch instruction.
 ;; For backward branches, the address calculation returns the address of
 ;; For a 'b'       pos_range = 2046, neg_range = -2048 giving (-2040->2048).
 ;; For a 'b<cond>' pos_range = 254,  neg_range = -256  giving (-250 ->256).
 
-(define_insn "cbranchsi4"
-  [(set (pc)
-       (if_then_else
-           (match_operator                    0 "arm_comparison_operator"
-                           [(match_operand:SI 1 "register_operand"   "l,r")
-                            (match_operand:SI 2 "nonmemory_operand" "rI,r")])
-           (label_ref       (match_operand    3 "" ""))
-           (pc)))]
+(define_expand "cbranchsi4"
+  [(set (pc) (if_then_else
+             (match_operator 0 "arm_comparison_operator"
+              [(match_operand:SI 1 "s_register_operand" "")
+               (match_operand:SI 2 "nonmemory_operand" "")])
+             (label_ref (match_operand 3 "" ""))
+             (pc)))]
+  "TARGET_THUMB"
+  "
+  if (thumb_cmpneg_operand (operands[2], SImode))
+    {
+      emit_jump_insn (gen_cbranchsi4_scratch (NULL, operands[1], operands[2],
+                                             operands[3], operands[0]));
+      DONE;
+    }
+  if (!thumb_cmp_operand (operands[2], SImode))
+    operands[2] = force_reg (SImode, operands[2]);
+  ")
+
+(define_insn "*cbranchsi4_insn"
+  [(set (pc) (if_then_else
+             (match_operator 0 "arm_comparison_operator"
+              [(match_operand:SI 1 "s_register_operand" "l,*h")
+               (match_operand:SI 2 "thumb_cmp_operand" "lI*h,*r")])
+             (label_ref (match_operand 3 "" ""))
+             (pc)))]
   "TARGET_THUMB"
   "*
   output_asm_insn (\"cmp\\t%1, %2\", operands);
+
   switch (get_attr_length (insn))
     {
     case 4:  return \"b%d0\\t%l3\";
                (const_int 8))))]
 )
 
+(define_insn "cbranchsi4_scratch"
+  [(set (pc) (if_then_else
+             (match_operator 4 "arm_comparison_operator"
+              [(match_operand:SI 1 "s_register_operand" "l,0")
+               (match_operand:SI 2 "thumb_cmpneg_operand" "L,J")])
+             (label_ref (match_operand 3 "" ""))
+             (pc)))
+   (clobber (match_scratch:SI 0 "=l,l"))]
+  "TARGET_THUMB"
+  "*
+  output_asm_insn (\"add\\t%0, %1, #%n2\", operands);
+
+  switch (get_attr_length (insn))
+    {
+    case 4:  return \"b%d4\\t%l3\";
+    case 6:  return \"b%D4\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
+    default: return \"b%D4\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
+    }
+  "
+  [(set (attr "far_jump")
+        (if_then_else
+           (eq_attr "length" "8")
+           (const_string "yes")
+            (const_string "no")))
+   (set (attr "length") 
+        (if_then_else
+           (and (ge (minus (match_dup 3) (pc)) (const_int -250))
+                (le (minus (match_dup 3) (pc)) (const_int 256)))
+           (const_int 4)
+           (if_then_else
+               (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
+                    (le (minus (match_dup 3) (pc)) (const_int 2048)))
+               (const_int 6)
+               (const_int 8))))]
+)
+(define_insn "*movsi_cbranchsi4"
+  [(set (pc)
+       (if_then_else
+        (match_operator 3 "arm_comparison_operator"
+         [(match_operand:SI 1 "s_register_operand" "0,l,l,l")
+          (const_int 0)])
+        (label_ref (match_operand 2 "" ""))
+        (pc)))
+   (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,l,*h,*m")
+       (match_dup 1))]
+  "TARGET_THUMB"
+  "*{
+  if (which_alternative == 0)
+    output_asm_insn (\"cmp\t%0, #0\", operands);
+  else if (which_alternative == 1)
+    output_asm_insn (\"sub\t%0, %1, #0\", operands);
+  else
+    {
+      output_asm_insn (\"cmp\t%1, #0\", operands);
+      if (which_alternative == 2)
+       output_asm_insn (\"mov\t%0, %1\", operands);
+      else
+       output_asm_insn (\"str\t%1, %0\", operands);
+    }
+  switch (get_attr_length (insn) - ((which_alternative > 1) ? 2 : 0))
+    {
+    case 4:  return \"b%d3\\t%l2\";
+    case 6:  return \"b%D3\\t.LCB%=\;b\\t%l2\\t%@long jump\\n.LCB%=:\";
+    default: return \"b%D3\\t.LCB%=\;bl\\t%l2\\t%@far jump\\n.LCB%=:\";
+    }
+  }"
+  [(set (attr "far_jump")
+        (if_then_else
+           (ior (and (gt (symbol_ref ("which_alternative"))
+                         (const_int 1))
+                     (eq_attr "length" "8"))
+                (eq_attr "length" "10"))
+           (const_string "yes")
+            (const_string "no")))
+   (set (attr "length")
+     (if_then_else
+       (le (symbol_ref ("which_alternative"))
+                      (const_int 1))
+       (if_then_else
+        (and (ge (minus (match_dup 2) (pc)) (const_int -250))
+             (le (minus (match_dup 2) (pc)) (const_int 256)))
+        (const_int 4)
+        (if_then_else
+          (and (ge (minus (match_dup 2) (pc)) (const_int -2040))
+               (le (minus (match_dup 2) (pc)) (const_int 2048)))
+          (const_int 6)
+          (const_int 8)))
+       (if_then_else
+        (and (ge (minus (match_dup 2) (pc)) (const_int -248))
+             (le (minus (match_dup 2) (pc)) (const_int 256)))
+        (const_int 6)
+        (if_then_else
+          (and (ge (minus (match_dup 2) (pc)) (const_int -2038))
+               (le (minus (match_dup 2) (pc)) (const_int 2048)))
+          (const_int 8)
+          (const_int 10)))))]
+)
+
 (define_insn "*negated_cbranchsi4"
   [(set (pc)
        (if_then_else
-        (match_operator             0 "arm_comparison_operator"
-         [(match_operand:SI         1 "register_operand"  "l")
-          (neg:SI (match_operand:SI 2 "nonmemory_operand" "l"))])
-        (label_ref (match_operand   3 "" ""))
+        (match_operator 0 "equality_operator"
+         [(match_operand:SI 1 "s_register_operand" "l")
+          (neg:SI (match_operand:SI 2 "s_register_operand" "l"))])
+        (label_ref (match_operand 3 "" ""))
         (pc)))]
   "TARGET_THUMB"
   "*
                (const_int 8))))]
 )
 
+(define_insn "*tbit_cbranch"
+  [(set (pc)
+       (if_then_else
+        (match_operator 0 "equality_operator"
+         [(zero_extract:SI (match_operand:SI 1 "s_register_operand" "l")
+                           (const_int 1)
+                           (match_operand:SI 2 "const_int_operand" "i"))
+          (const_int 0)])
+        (label_ref (match_operand 3 "" ""))
+        (pc)))
+   (clobber (match_scratch:SI 4 "=l"))]
+  "TARGET_THUMB"
+  "*
+  {
+  rtx op[3];
+  op[0] = operands[4];
+  op[1] = operands[1];
+  op[2] = GEN_INT (32 - 1 - INTVAL (operands[2]));
+
+  output_asm_insn (\"lsl\\t%0, %1, %2\", op);
+  switch (get_attr_length (insn))
+    {
+    case 4:  return \"b%d0\\t%l3\";
+    case 6:  return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
+    default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
+    }
+  }"
+  [(set (attr "far_jump")
+        (if_then_else
+           (eq_attr "length" "8")
+           (const_string "yes")
+            (const_string "no")))
+   (set (attr "length") 
+        (if_then_else
+           (and (ge (minus (match_dup 3) (pc)) (const_int -250))
+                (le (minus (match_dup 3) (pc)) (const_int 256)))
+           (const_int 4)
+           (if_then_else
+               (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
+                    (le (minus (match_dup 3) (pc)) (const_int 2048)))
+               (const_int 6)
+               (const_int 8))))]
+)
+  
+(define_insn "*tstsi3_cbranch"
+  [(set (pc)
+       (if_then_else
+        (match_operator 3 "equality_operator"
+         [(and:SI (match_operand:SI 0 "s_register_operand" "%l")
+                  (match_operand:SI 1 "s_register_operand" "l"))
+          (const_int 0)])
+        (label_ref (match_operand 2 "" ""))
+        (pc)))]
+  "TARGET_THUMB"
+  "*
+  {
+  output_asm_insn (\"tst\\t%0, %1\", operands);
+  switch (get_attr_length (insn))
+    {
+    case 4:  return \"b%d3\\t%l2\";
+    case 6:  return \"b%D3\\t.LCB%=\;b\\t%l2\\t%@long jump\\n.LCB%=:\";
+    default: return \"b%D3\\t.LCB%=\;bl\\t%l2\\t%@far jump\\n.LCB%=:\";
+    }
+  }"
+  [(set (attr "far_jump")
+        (if_then_else
+           (eq_attr "length" "8")
+           (const_string "yes")
+            (const_string "no")))
+   (set (attr "length") 
+        (if_then_else
+           (and (ge (minus (match_dup 2) (pc)) (const_int -250))
+                (le (minus (match_dup 2) (pc)) (const_int 256)))
+           (const_int 4)
+           (if_then_else
+               (and (ge (minus (match_dup 2) (pc)) (const_int -2040))
+                    (le (minus (match_dup 2) (pc)) (const_int 2048)))
+               (const_int 6)
+               (const_int 8))))]
+)
+  
+(define_insn "*andsi3_cbranch"
+  [(set (pc)
+       (if_then_else
+        (match_operator 5 "equality_operator"
+         [(and:SI (match_operand:SI 2 "s_register_operand" "%0,1,1,1")
+                  (match_operand:SI 3 "s_register_operand" "l,l,l,l"))
+          (const_int 0)])
+        (label_ref (match_operand 4 "" ""))
+        (pc)))
+   (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,*?h,*?m,*?m")
+       (and:SI (match_dup 2) (match_dup 3)))
+   (clobber (match_scratch:SI 1 "=X,l,&l,&l"))]
+  "TARGET_THUMB"
+  "*
+  {
+  if (which_alternative == 0)
+    output_asm_insn (\"and\\t%0, %3\", operands);
+  else if (which_alternative == 1)
+    {
+      output_asm_insn (\"and\\t%1, %3\", operands);
+      output_asm_insn (\"mov\\t%0, %1\", operands);
+    }
+  else
+    {
+      output_asm_insn (\"and\\t%1, %3\", operands);
+      output_asm_insn (\"str\\t%1, %0\", operands);
+    }
+
+  switch (get_attr_length (insn) - (which_alternative ? 2 : 0))
+    {
+    case 4:  return \"b%d5\\t%l4\";
+    case 6:  return \"b%D5\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\";
+    default: return \"b%D5\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\";
+    }
+  }"
+  [(set (attr "far_jump")
+        (if_then_else
+           (ior (and (eq (symbol_ref ("which_alternative"))
+                         (const_int 0))
+                     (eq_attr "length" "8"))
+                (eq_attr "length" "10"))
+           (const_string "yes")
+            (const_string "no")))
+   (set (attr "length")
+     (if_then_else
+       (eq (symbol_ref ("which_alternative"))
+                      (const_int 0))
+       (if_then_else
+        (and (ge (minus (match_dup 4) (pc)) (const_int -250))
+             (le (minus (match_dup 4) (pc)) (const_int 256)))
+        (const_int 4)
+        (if_then_else
+          (and (ge (minus (match_dup 4) (pc)) (const_int -2040))
+               (le (minus (match_dup 4) (pc)) (const_int 2048)))
+          (const_int 6)
+          (const_int 8)))
+       (if_then_else
+        (and (ge (minus (match_dup 4) (pc)) (const_int -248))
+             (le (minus (match_dup 4) (pc)) (const_int 256)))
+        (const_int 6)
+        (if_then_else
+          (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
+               (le (minus (match_dup 4) (pc)) (const_int 2048)))
+          (const_int 8)
+          (const_int 10)))))]
+)
+
+(define_insn "*orrsi3_cbranch_scratch"
+  [(set (pc)
+       (if_then_else
+        (match_operator 4 "equality_operator"
+         [(ior:SI (match_operand:SI 1 "s_register_operand" "%0")
+                  (match_operand:SI 2 "s_register_operand" "l"))
+          (const_int 0)])
+        (label_ref (match_operand 3 "" ""))
+        (pc)))
+   (clobber (match_scratch:SI 0 "=l"))]
+  "TARGET_THUMB"
+  "*
+  {
+  output_asm_insn (\"orr\\t%0, %2\", operands);
+  switch (get_attr_length (insn))
+    {
+    case 4:  return \"b%d4\\t%l3\";
+    case 6:  return \"b%D4\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
+    default: return \"b%D4\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
+    }
+  }"
+  [(set (attr "far_jump")
+        (if_then_else
+           (eq_attr "length" "8")
+           (const_string "yes")
+            (const_string "no")))
+   (set (attr "length") 
+        (if_then_else
+           (and (ge (minus (match_dup 3) (pc)) (const_int -250))
+                (le (minus (match_dup 3) (pc)) (const_int 256)))
+           (const_int 4)
+           (if_then_else
+               (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
+                    (le (minus (match_dup 3) (pc)) (const_int 2048)))
+               (const_int 6)
+               (const_int 8))))]
+)
+  
+(define_insn "*orrsi3_cbranch"
+  [(set (pc)
+       (if_then_else
+        (match_operator 5 "equality_operator"
+         [(ior:SI (match_operand:SI 2 "s_register_operand" "%0,1,1,1")
+                  (match_operand:SI 3 "s_register_operand" "l,l,l,l"))
+          (const_int 0)])
+        (label_ref (match_operand 4 "" ""))
+        (pc)))
+   (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,*?h,*?m,*?m")
+       (ior:SI (match_dup 2) (match_dup 3)))
+   (clobber (match_scratch:SI 1 "=X,l,&l,&l"))]
+  "TARGET_THUMB"
+  "*
+  {
+  if (which_alternative == 0)
+    output_asm_insn (\"orr\\t%0, %3\", operands);
+  else if (which_alternative == 1)
+    {
+      output_asm_insn (\"orr\\t%1, %3\", operands);
+      output_asm_insn (\"mov\\t%0, %1\", operands);
+    }
+  else
+    {
+      output_asm_insn (\"orr\\t%1, %3\", operands);
+      output_asm_insn (\"str\\t%1, %0\", operands);
+    }
+
+  switch (get_attr_length (insn) - (which_alternative ? 2 : 0))
+    {
+    case 4:  return \"b%d5\\t%l4\";
+    case 6:  return \"b%D5\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\";
+    default: return \"b%D5\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\";
+    }
+  }"
+  [(set (attr "far_jump")
+        (if_then_else
+           (ior (and (eq (symbol_ref ("which_alternative"))
+                         (const_int 0))
+                     (eq_attr "length" "8"))
+                (eq_attr "length" "10"))
+           (const_string "yes")
+            (const_string "no")))
+   (set (attr "length")
+     (if_then_else
+       (eq (symbol_ref ("which_alternative"))
+                      (const_int 0))
+       (if_then_else
+        (and (ge (minus (match_dup 4) (pc)) (const_int -250))
+             (le (minus (match_dup 4) (pc)) (const_int 256)))
+        (const_int 4)
+        (if_then_else
+          (and (ge (minus (match_dup 4) (pc)) (const_int -2040))
+               (le (minus (match_dup 4) (pc)) (const_int 2048)))
+          (const_int 6)
+          (const_int 8)))
+       (if_then_else
+        (and (ge (minus (match_dup 4) (pc)) (const_int -248))
+             (le (minus (match_dup 4) (pc)) (const_int 256)))
+        (const_int 6)
+        (if_then_else
+          (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
+               (le (minus (match_dup 4) (pc)) (const_int 2048)))
+          (const_int 8)
+          (const_int 10)))))]
+)
+
+(define_insn "*xorsi3_cbranch_scratch"
+  [(set (pc)
+       (if_then_else
+        (match_operator 4 "equality_operator"
+         [(xor:SI (match_operand:SI 1 "s_register_operand" "%0")
+                  (match_operand:SI 2 "s_register_operand" "l"))
+          (const_int 0)])
+        (label_ref (match_operand 3 "" ""))
+        (pc)))
+   (clobber (match_scratch:SI 0 "=l"))]
+  "TARGET_THUMB"
+  "*
+  {
+  output_asm_insn (\"eor\\t%0, %2\", operands);
+  switch (get_attr_length (insn))
+    {
+    case 4:  return \"b%d4\\t%l3\";
+    case 6:  return \"b%D4\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
+    default: return \"b%D4\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
+    }
+  }"
+  [(set (attr "far_jump")
+        (if_then_else
+           (eq_attr "length" "8")
+           (const_string "yes")
+            (const_string "no")))
+   (set (attr "length") 
+        (if_then_else
+           (and (ge (minus (match_dup 3) (pc)) (const_int -250))
+                (le (minus (match_dup 3) (pc)) (const_int 256)))
+           (const_int 4)
+           (if_then_else
+               (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
+                    (le (minus (match_dup 3) (pc)) (const_int 2048)))
+               (const_int 6)
+               (const_int 8))))]
+)
+  
+(define_insn "*xorsi3_cbranch"
+  [(set (pc)
+       (if_then_else
+        (match_operator 5 "equality_operator"
+         [(xor:SI (match_operand:SI 2 "s_register_operand" "%0,1,1,1")
+                  (match_operand:SI 3 "s_register_operand" "l,l,l,l"))
+          (const_int 0)])
+        (label_ref (match_operand 4 "" ""))
+        (pc)))
+   (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,*?h,*?m,*?m")
+       (xor:SI (match_dup 2) (match_dup 3)))
+   (clobber (match_scratch:SI 1 "=X,l,&l,&l"))]
+  "TARGET_THUMB"
+  "*
+  {
+  if (which_alternative == 0)
+    output_asm_insn (\"eor\\t%0, %3\", operands);
+  else if (which_alternative == 1)
+    {
+      output_asm_insn (\"eor\\t%1, %3\", operands);
+      output_asm_insn (\"mov\\t%0, %1\", operands);
+    }
+  else
+    {
+      output_asm_insn (\"eor\\t%1, %3\", operands);
+      output_asm_insn (\"str\\t%1, %0\", operands);
+    }
+
+  switch (get_attr_length (insn) - (which_alternative ? 2 : 0))
+    {
+    case 4:  return \"b%d5\\t%l4\";
+    case 6:  return \"b%D5\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\";
+    default: return \"b%D5\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\";
+    }
+  }"
+  [(set (attr "far_jump")
+        (if_then_else
+           (ior (and (eq (symbol_ref ("which_alternative"))
+                         (const_int 0))
+                     (eq_attr "length" "8"))
+                (eq_attr "length" "10"))
+           (const_string "yes")
+            (const_string "no")))
+   (set (attr "length")
+     (if_then_else
+       (eq (symbol_ref ("which_alternative"))
+                      (const_int 0))
+       (if_then_else
+        (and (ge (minus (match_dup 4) (pc)) (const_int -250))
+             (le (minus (match_dup 4) (pc)) (const_int 256)))
+        (const_int 4)
+        (if_then_else
+          (and (ge (minus (match_dup 4) (pc)) (const_int -2040))
+               (le (minus (match_dup 4) (pc)) (const_int 2048)))
+          (const_int 6)
+          (const_int 8)))
+       (if_then_else
+        (and (ge (minus (match_dup 4) (pc)) (const_int -248))
+             (le (minus (match_dup 4) (pc)) (const_int 256)))
+        (const_int 6)
+        (if_then_else
+          (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
+               (le (minus (match_dup 4) (pc)) (const_int 2048)))
+          (const_int 8)
+          (const_int 10)))))]
+)
+
+(define_insn "*bicsi3_cbranch_scratch"
+  [(set (pc)
+       (if_then_else
+        (match_operator 4 "equality_operator"
+         [(and:SI (not:SI (match_operand:SI 2 "s_register_operand" "l"))
+                  (match_operand:SI 1 "s_register_operand" "0"))
+          (const_int 0)])
+        (label_ref (match_operand 3 "" ""))
+        (pc)))
+   (clobber (match_scratch:SI 0 "=l"))]
+  "TARGET_THUMB"
+  "*
+  {
+  output_asm_insn (\"bic\\t%0, %2\", operands);
+  switch (get_attr_length (insn))
+    {
+    case 4:  return \"b%d4\\t%l3\";
+    case 6:  return \"b%D4\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
+    default: return \"b%D4\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
+    }
+  }"
+  [(set (attr "far_jump")
+        (if_then_else
+           (eq_attr "length" "8")
+           (const_string "yes")
+            (const_string "no")))
+   (set (attr "length") 
+        (if_then_else
+           (and (ge (minus (match_dup 3) (pc)) (const_int -250))
+                (le (minus (match_dup 3) (pc)) (const_int 256)))
+           (const_int 4)
+           (if_then_else
+               (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
+                    (le (minus (match_dup 3) (pc)) (const_int 2048)))
+               (const_int 6)
+               (const_int 8))))]
+)
+  
+(define_insn "*bicsi3_cbranch"
+  [(set (pc)
+       (if_then_else
+        (match_operator 5 "equality_operator"
+         [(and:SI (not:SI (match_operand:SI 3 "s_register_operand" "l,l,l,l,l"))
+                  (match_operand:SI 2 "s_register_operand" "0,1,1,1,1"))
+          (const_int 0)])
+        (label_ref (match_operand 4 "" ""))
+        (pc)))
+   (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=!l,l,*?h,*?m,*?m")
+       (and:SI (not:SI (match_dup 3)) (match_dup 2)))
+   (clobber (match_scratch:SI 1 "=X,l,l,&l,&l"))]
+  "TARGET_THUMB"
+  "*
+  {
+  if (which_alternative == 0)
+    output_asm_insn (\"bic\\t%0, %3\", operands);
+  else if (which_alternative <= 2)
+    {
+      output_asm_insn (\"bic\\t%1, %3\", operands);
+      /* It's ok if OP0 is a lo-reg, even though the mov will set the
+        conditions again, since we're only testing for equality.  */
+      output_asm_insn (\"mov\\t%0, %1\", operands);
+    }
+  else
+    {
+      output_asm_insn (\"bic\\t%1, %3\", operands);
+      output_asm_insn (\"str\\t%1, %0\", operands);
+    }
+
+  switch (get_attr_length (insn) - (which_alternative ? 2 : 0))
+    {
+    case 4:  return \"b%d5\\t%l4\";
+    case 6:  return \"b%D5\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\";
+    default: return \"b%D5\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\";
+    }
+  }"
+  [(set (attr "far_jump")
+        (if_then_else
+           (ior (and (eq (symbol_ref ("which_alternative"))
+                         (const_int 0))
+                     (eq_attr "length" "8"))
+                (eq_attr "length" "10"))
+           (const_string "yes")
+            (const_string "no")))
+   (set (attr "length")
+     (if_then_else
+       (eq (symbol_ref ("which_alternative"))
+                      (const_int 0))
+       (if_then_else
+        (and (ge (minus (match_dup 4) (pc)) (const_int -250))
+             (le (minus (match_dup 4) (pc)) (const_int 256)))
+        (const_int 4)
+        (if_then_else
+          (and (ge (minus (match_dup 4) (pc)) (const_int -2040))
+               (le (minus (match_dup 4) (pc)) (const_int 2048)))
+          (const_int 6)
+          (const_int 8)))
+       (if_then_else
+        (and (ge (minus (match_dup 4) (pc)) (const_int -248))
+             (le (minus (match_dup 4) (pc)) (const_int 256)))
+        (const_int 6)
+        (if_then_else
+          (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
+               (le (minus (match_dup 4) (pc)) (const_int 2048)))
+          (const_int 8)
+          (const_int 10)))))]
+)
+
+(define_insn "*cbranchne_decr1"
+  [(set (pc)
+       (if_then_else (match_operator 3 "equality_operator"
+                      [(match_operand:SI 2 "s_register_operand" "l,l,1,l")
+                       (const_int 0)])
+                     (label_ref (match_operand 4 "" ""))
+                     (pc)))
+   (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,*?h,*?m,*?m")
+       (plus:SI (match_dup 2) (const_int -1)))
+   (clobber (match_scratch:SI 1 "=X,l,&l,&l"))]
+  "TARGET_THUMB"
+  "*
+   {
+     rtx cond[2];
+     cond[0] = gen_rtx_fmt_ee ((GET_CODE (operands[3]) == NE
+                               ? GEU : LTU),
+                              VOIDmode, operands[2], const1_rtx);
+     cond[1] = operands[4];
+
+     if (which_alternative == 0)
+       output_asm_insn (\"sub\\t%0, %2, #1\", operands);
+     else if (which_alternative == 1)
+       {
+        /* We must provide an alternative for a hi reg because reload 
+           cannot handle output reloads on a jump instruction, but we
+           can't subtract into that.  Fortunately a mov from lo to hi
+           does not clobber the condition codes.  */
+        output_asm_insn (\"sub\\t%1, %2, #1\", operands);
+        output_asm_insn (\"mov\\t%0, %1\", operands);
+       }
+     else
+       {
+        /* Similarly, but the target is memory.  */
+        output_asm_insn (\"sub\\t%1, %2, #1\", operands);
+        output_asm_insn (\"str\\t%1, %0\", operands);
+       }
+
+     switch (get_attr_length (insn) - (which_alternative ? 2 : 0))
+       {
+        case 4:
+          output_asm_insn (\"b%d0\\t%l1\", cond);
+          return \"\";
+        case 6:
+          output_asm_insn (\"b%D0\\t.LCB%=\", cond);
+          return \"b\\t%l4\\t%@long jump\\n.LCB%=:\";
+        default:
+          output_asm_insn (\"b%D0\\t.LCB%=\", cond);
+          return \"bl\\t%l4\\t%@far jump\\n.LCB%=:\";
+       }
+   }
+  "
+  [(set (attr "far_jump")
+        (if_then_else
+           (ior (and (eq (symbol_ref ("which_alternative"))
+                         (const_int 0))
+                     (eq_attr "length" "8"))
+                (eq_attr "length" "10"))
+           (const_string "yes")
+            (const_string "no")))
+   (set_attr_alternative "length"
+      [
+       ;; Alternative 0
+       (if_then_else
+        (and (ge (minus (match_dup 4) (pc)) (const_int -250))
+             (le (minus (match_dup 4) (pc)) (const_int 256)))
+        (const_int 4)
+        (if_then_else
+          (and (ge (minus (match_dup 4) (pc)) (const_int -2040))
+               (le (minus (match_dup 4) (pc)) (const_int 2048)))
+          (const_int 6)
+          (const_int 8)))
+       ;; Alternative 1
+       (if_then_else
+        (and (ge (minus (match_dup 4) (pc)) (const_int -248))
+             (le (minus (match_dup 4) (pc)) (const_int 256)))
+        (const_int 6)
+        (if_then_else
+          (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
+               (le (minus (match_dup 4) (pc)) (const_int 2048)))
+          (const_int 8)
+          (const_int 10)))
+       ;; Alternative 2
+       (if_then_else
+        (and (ge (minus (match_dup 4) (pc)) (const_int -248))
+             (le (minus (match_dup 4) (pc)) (const_int 256)))
+        (const_int 6)
+        (if_then_else
+          (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
+               (le (minus (match_dup 4) (pc)) (const_int 2048)))
+          (const_int 8)
+          (const_int 10)))
+       ;; Alternative 3
+       (if_then_else
+        (and (ge (minus (match_dup 4) (pc)) (const_int -248))
+             (le (minus (match_dup 4) (pc)) (const_int 256)))
+        (const_int 6)
+        (if_then_else
+          (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
+               (le (minus (match_dup 4) (pc)) (const_int 2048)))
+          (const_int 8)
+          (const_int 10)))])]
+)
+
+(define_insn "*addsi3_cbranch"
+  [(set (pc)
+       (if_then_else
+        (match_operator 4 "comparison_operator"
+         [(plus:SI
+           (match_operand:SI 2 "s_register_operand" "%l,0,*0,1,1,1")
+           (match_operand:SI 3 "reg_or_int_operand" "lL,IJ,*r,lIJ,lIJ,lIJ"))
+          (const_int 0)])
+        (label_ref (match_operand 5 "" ""))
+        (pc)))
+   (set
+    (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,l,*!h,*?h,*?m,*?m")
+    (plus:SI (match_dup 2) (match_dup 3)))
+   (clobber (match_scratch:SI 1 "=X,X,X,l,&l,&l"))]
+  "TARGET_THUMB
+   && (GET_CODE (operands[4]) == EQ
+       || GET_CODE (operands[4]) == NE
+       || GET_CODE (operands[4]) == GE
+       || GET_CODE (operands[4]) == LT)"
+  "*
+   {
+     rtx cond[3];
+
+     
+     cond[0] = (which_alternative < 3) ? operands[0] : operands[1];
+     cond[1] = operands[2];
+     cond[2] = operands[3];
+
+     if (GET_CODE (cond[2]) == CONST_INT && INTVAL (cond[2]) < 0)
+       output_asm_insn (\"sub\\t%0, %1, #%n2\", cond);
+     else
+       output_asm_insn (\"add\\t%0, %1, %2\", cond);
+
+     if (which_alternative >= 3
+        && which_alternative < 4)
+       output_asm_insn (\"mov\\t%0, %1\", operands);
+     else if (which_alternative >= 4)
+       output_asm_insn (\"str\\t%1, %0\", operands);
+
+     switch (get_attr_length (insn) - ((which_alternative >= 3) ? 2 : 0))
+       {
+        case 4:
+          return \"b%d4\\t%l5\";
+        case 6:
+          return \"b%D4\\t.LCB%=\;b\\t%l5\\t%@long jump\\n.LCB%=:\";
+        default:
+          return \"b%D4\\t.LCB%=\;bl\\t%l5\\t%@far jump\\n.LCB%=:\";
+       }
+   }
+  "
+  [(set (attr "far_jump")
+        (if_then_else
+           (ior (and (lt (symbol_ref ("which_alternative"))
+                         (const_int 3))
+                     (eq_attr "length" "8"))
+                (eq_attr "length" "10"))
+           (const_string "yes")
+            (const_string "no")))
+   (set (attr "length")
+     (if_then_else
+       (lt (symbol_ref ("which_alternative"))
+                      (const_int 3))
+       (if_then_else
+        (and (ge (minus (match_dup 5) (pc)) (const_int -250))
+             (le (minus (match_dup 5) (pc)) (const_int 256)))
+        (const_int 4)
+        (if_then_else
+          (and (ge (minus (match_dup 5) (pc)) (const_int -2040))
+               (le (minus (match_dup 5) (pc)) (const_int 2048)))
+          (const_int 6)
+          (const_int 8)))
+       (if_then_else
+        (and (ge (minus (match_dup 5) (pc)) (const_int -248))
+             (le (minus (match_dup 5) (pc)) (const_int 256)))
+        (const_int 6)
+        (if_then_else
+          (and (ge (minus (match_dup 5) (pc)) (const_int -2038))
+               (le (minus (match_dup 5) (pc)) (const_int 2048)))
+          (const_int 8)
+          (const_int 10)))))]
+)
+
+(define_insn "*addsi3_cbranch_scratch"
+  [(set (pc)
+       (if_then_else
+        (match_operator 3 "comparison_operator"
+         [(plus:SI
+           (match_operand:SI 1 "s_register_operand" "%l,l,l,0")
+           (match_operand:SI 2 "reg_or_int_operand" "J,l,L,IJ"))
+          (const_int 0)])
+        (label_ref (match_operand 4 "" ""))
+        (pc)))
+   (clobber (match_scratch:SI 0 "=X,X,l,l"))]
+  "TARGET_THUMB
+   && (GET_CODE (operands[3]) == EQ
+       || GET_CODE (operands[3]) == NE
+       || GET_CODE (operands[3]) == GE
+       || GET_CODE (operands[3]) == LT)"
+  "*
+   {
+     switch (which_alternative)
+       {
+       case 0:
+        output_asm_insn (\"cmp\t%1, #%n2\", operands);
+        break;
+       case 1:
+        output_asm_insn (\"cmn\t%1, %2\", operands);
+        break;
+       case 2:
+        if (INTVAL (operands[2]) < 0)
+          output_asm_insn (\"sub\t%0, %1, %2\", operands);
+        else
+          output_asm_insn (\"add\t%0, %1, %2\", operands);
+        break;
+       case 3:
+        if (INTVAL (operands[2]) < 0)
+          output_asm_insn (\"sub\t%0, %0, %2\", operands);
+        else
+          output_asm_insn (\"add\t%0, %0, %2\", operands);
+        break;
+       }
+
+     switch (get_attr_length (insn))
+       {
+        case 4:
+          return \"b%d3\\t%l4\";
+        case 6:
+          return \"b%D3\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\";
+        default:
+          return \"b%D3\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\";
+       }
+   }
+  "
+  [(set (attr "far_jump")
+        (if_then_else
+           (eq_attr "length" "8")
+           (const_string "yes")
+            (const_string "no")))
+   (set (attr "length")
+       (if_then_else
+        (and (ge (minus (match_dup 4) (pc)) (const_int -250))
+             (le (minus (match_dup 4) (pc)) (const_int 256)))
+        (const_int 4)
+        (if_then_else
+          (and (ge (minus (match_dup 4) (pc)) (const_int -2040))
+               (le (minus (match_dup 4) (pc)) (const_int 2048)))
+          (const_int 6)
+          (const_int 8))))]
+)
+
+(define_insn "*subsi3_cbranch"
+  [(set (pc)
+       (if_then_else
+        (match_operator 4 "comparison_operator"
+         [(minus:SI
+           (match_operand:SI 2 "s_register_operand" "l,l,1,l")
+           (match_operand:SI 3 "s_register_operand" "l,l,l,l"))
+          (const_int 0)])
+        (label_ref (match_operand 5 "" ""))
+        (pc)))
+   (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,*?h,*?m,*?m")
+       (minus:SI (match_dup 2) (match_dup 3)))
+   (clobber (match_scratch:SI 1 "=X,l,&l,&l"))]
+  "TARGET_THUMB
+   && (GET_CODE (operands[4]) == EQ
+       || GET_CODE (operands[4]) == NE
+       || GET_CODE (operands[4]) == GE
+       || GET_CODE (operands[4]) == LT)"
+  "*
+   {
+     if (which_alternative == 0)
+       output_asm_insn (\"sub\\t%0, %2, %3\", operands);
+     else if (which_alternative == 1)
+       {
+        /* We must provide an alternative for a hi reg because reload 
+           cannot handle output reloads on a jump instruction, but we
+           can't subtract into that.  Fortunately a mov from lo to hi
+           does not clobber the condition codes.  */
+        output_asm_insn (\"sub\\t%1, %2, %3\", operands);
+        output_asm_insn (\"mov\\t%0, %1\", operands);
+       }
+     else
+       {
+        /* Similarly, but the target is memory.  */
+        output_asm_insn (\"sub\\t%1, %2, %3\", operands);
+        output_asm_insn (\"str\\t%1, %0\", operands);
+       }
+
+     switch (get_attr_length (insn) - ((which_alternative != 0) ? 2 : 0))
+       {
+        case 4:
+          return \"b%d4\\t%l5\";
+        case 6:
+          return \"b%D4\\t.LCB%=\;b\\t%l5\\t%@long jump\\n.LCB%=:\";
+        default:
+          return \"b%D4\\t.LCB%=\;bl\\t%l5\\t%@far jump\\n.LCB%=:\";
+       }
+   }
+  "
+  [(set (attr "far_jump")
+        (if_then_else
+           (ior (and (eq (symbol_ref ("which_alternative"))
+                         (const_int 0))
+                     (eq_attr "length" "8"))
+                (eq_attr "length" "10"))
+           (const_string "yes")
+            (const_string "no")))
+   (set (attr "length")
+     (if_then_else
+       (eq (symbol_ref ("which_alternative"))
+                      (const_int 0))
+       (if_then_else
+        (and (ge (minus (match_dup 5) (pc)) (const_int -250))
+             (le (minus (match_dup 5) (pc)) (const_int 256)))
+        (const_int 4)
+        (if_then_else
+          (and (ge (minus (match_dup 5) (pc)) (const_int -2040))
+               (le (minus (match_dup 5) (pc)) (const_int 2048)))
+          (const_int 6)
+          (const_int 8)))
+       (if_then_else
+        (and (ge (minus (match_dup 5) (pc)) (const_int -248))
+             (le (minus (match_dup 5) (pc)) (const_int 256)))
+        (const_int 6)
+        (if_then_else
+          (and (ge (minus (match_dup 5) (pc)) (const_int -2038))
+               (le (minus (match_dup 5) (pc)) (const_int 2048)))
+          (const_int 8)
+          (const_int 10)))))]
+)
+
+(define_insn "*subsi3_cbranch_scratch"
+  [(set (pc)
+       (if_then_else
+        (match_operator 0 "arm_comparison_operator"
+         [(minus:SI (match_operand:SI 1 "register_operand" "l")
+                    (match_operand:SI 2 "nonmemory_operand" "l"))
+          (const_int 0)])
+        (label_ref (match_operand 3 "" ""))
+        (pc)))]
+  "TARGET_THUMB
+   && (GET_CODE (operands[0]) == EQ
+       || GET_CODE (operands[0]) == NE
+       || GET_CODE (operands[0]) == GE
+       || GET_CODE (operands[0]) == LT)"
+  "*
+  output_asm_insn (\"cmp\\t%1, %2\", operands);
+  switch (get_attr_length (insn))
+    {
+    case 4:  return \"b%d0\\t%l3\";
+    case 6:  return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
+    default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
+    }
+  "
+  [(set (attr "far_jump")
+        (if_then_else
+           (eq_attr "length" "8")
+           (const_string "yes")
+            (const_string "no")))
+   (set (attr "length") 
+        (if_then_else
+           (and (ge (minus (match_dup 3) (pc)) (const_int -250))
+                (le (minus (match_dup 3) (pc)) (const_int 256)))
+           (const_int 4)
+           (if_then_else
+               (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
+                    (le (minus (match_dup 3) (pc)) (const_int 2048)))
+               (const_int 6)
+               (const_int 8))))]
+)
 
 ;; Comparison and test insns
 
 
 (define_expand "cmpsf"
   [(match_operand:SF 0 "s_register_operand" "")
-   (match_operand:SF 1 "fpu_rhs_operand" "")]
-  "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
+   (match_operand:SF 1 "arm_float_compare_operand" "")]
+  "TARGET_ARM && TARGET_HARD_FLOAT"
   "
-  if (TARGET_CIRRUS && !cirrus_fp_register (operands[1], SFmode))
-    operands[1] = force_reg (SFmode, operands[1]);
-
   arm_compare_op0 = operands[0];
   arm_compare_op1 = operands[1];
   DONE;
 
 (define_expand "cmpdf"
   [(match_operand:DF 0 "s_register_operand" "")
-   (match_operand:DF 1 "fpu_rhs_operand" "")]
-  "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
+   (match_operand:DF 1 "arm_float_compare_operand" "")]
+  "TARGET_ARM && TARGET_HARD_FLOAT"
   "
-  if (TARGET_CIRRUS && !cirrus_fp_register (operands[1], DFmode))
-    operands[1] = force_reg (DFmode, operands[1]);
-
   arm_compare_op0 = operands[0];
   arm_compare_op1 = operands[1];
   DONE;
   "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")))]
 )
 
 (define_insn "*cmpsi_shiftsi_swp"
   "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")))]
 )
 
-(define_insn "*cmpsi_neg_shiftsi"
-  [(set (reg:CC CC_REGNUM)
-       (compare:CC (match_operand:SI 0 "s_register_operand" "r")
-                   (neg:SI (match_operator:SI 3 "shift_operator"
-                            [(match_operand:SI 1 "s_register_operand" "r")
-                             (match_operand:SI 2 "arm_rhs_operand" "rM")]))))]
+(define_insn "*cmpsi_negshiftsi_si"
+  [(set (reg:CC_Z CC_REGNUM)
+       (compare:CC_Z
+        (neg:SI (match_operator:SI 1 "shift_operator"
+                   [(match_operand:SI 2 "s_register_operand" "r")
+                    (match_operand:SI 3 "reg_or_int_operand" "rM")]))
+        (match_operand:SI 0 "s_register_operand" "r")))]
   "TARGET_ARM"
-  "cmn%?\\t%0, %1%S3"
-  [(set_attr "conds" "set")
-   (set_attr "shift" "1")
-   ]
-)
-
-(define_insn "*cmpsf_insn"
-  [(set (reg:CCFP CC_REGNUM)
-       (compare:CCFP (match_operand:SF 0 "s_register_operand" "f,f")
-                     (match_operand:SF 1 "fpu_add_operand" "fG,H")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "@
-   cmf%?\\t%0, %1
-   cnf%?\\t%0, #%N1"
+  "cmn%?\\t%0, %2%S1"
   [(set_attr "conds" "set")
-   (set_attr "type" "f_2_r")]
+   (set (attr "type") (if_then_else (match_operand 3 "const_int_operand" "")
+                                   (const_string "alu_shift")
+                                   (const_string "alu_shift_reg")))]
 )
 
-(define_insn "*cmpdf_insn"
-  [(set (reg:CCFP CC_REGNUM)
-       (compare:CCFP (match_operand:DF 0 "s_register_operand" "f,f")
-                     (match_operand:DF 1 "fpu_add_operand" "fG,H")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "@
-   cmf%?\\t%0, %1
-   cnf%?\\t%0, #%N1"
-  [(set_attr "conds" "set")
-   (set_attr "type" "f_2_r")]
-)
-
-(define_insn "*cmpesfdf_df"
-  [(set (reg:CCFP CC_REGNUM)
-       (compare:CCFP (float_extend:DF
-                      (match_operand:SF 0 "s_register_operand" "f,f"))
-                     (match_operand:DF 1 "fpu_add_operand" "fG,H")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "@
-   cmf%?\\t%0, %1
-   cnf%?\\t%0, #%N1"
-  [(set_attr "conds" "set")
-   (set_attr "type" "f_2_r")]
-)
-
-(define_insn "*cmpdf_esfdf"
-  [(set (reg:CCFP CC_REGNUM)
-       (compare:CCFP (match_operand:DF 0 "s_register_operand" "f")
-                     (float_extend:DF
-                      (match_operand:SF 1 "s_register_operand" "f"))))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "cmf%?\\t%0, %1"
-  [(set_attr "conds" "set")
-   (set_attr "type" "f_2_r")]
-)
-
-;; There is no CCFPE or CCFP modes in the code below so we can have
-;; one pattern to match either one.  Besides, we're pretty sure we
-;; have either CCFPE or CCFP because we made the patterns
-;; (arm_gen_compare_reg).
-
 ;; Cirrus SF compare instruction
 (define_insn "*cirrus_cmpsf"
   [(set (reg:CCFP CC_REGNUM)
        (compare:CCFP (match_operand:SF 0 "cirrus_fp_register" "v")
                      (match_operand:SF 1 "cirrus_fp_register" "v")))]
-  "TARGET_ARM && TARGET_CIRRUS"
+  "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
   "cfcmps%?\\tr15, %V0, %V1"
-  [(set_attr "cirrus_type" "farith")
+  [(set_attr "type"   "mav_farith")
    (set_attr "cirrus" "compare")]
 )
 
   [(set (reg:CCFP CC_REGNUM)
        (compare:CCFP (match_operand:DF 0 "cirrus_fp_register" "v")
                      (match_operand:DF 1 "cirrus_fp_register" "v")))]
-  "TARGET_ARM && TARGET_CIRRUS"
+  "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
   "cfcmpd%?\\tr15, %V0, %V1"
-  [(set_attr "cirrus_type" "farith")
+  [(set_attr "type"   "mav_farith")
    (set_attr "cirrus" "compare")]
 )
 
 (define_expand "cmpdi"
   [(match_operand:DI 0 "cirrus_fp_register" "")
    (match_operand:DI 1 "cirrus_fp_register" "")]
-  "TARGET_ARM && TARGET_CIRRUS"
-  "{
-     arm_compare_op0 = operands[0];
-     arm_compare_op1 = operands[1];
-     DONE;
-   }")
-
-(define_insn "*cirrus_cmpdi"
-  [(set (reg:CC CC_REGNUM)
-       (compare:CC (match_operand:DI 0 "cirrus_fp_register" "v")
-                   (match_operand:DI 1 "cirrus_fp_register" "v")))]
-  "TARGET_ARM && TARGET_CIRRUS"
-  "cfcmp64%?\\tr15, %V0, %V1"
-  [(set_attr "cirrus_type" "farith")
-   (set_attr "cirrus" "compare")]
-)
-
-;; Cirrus SI compare instruction
-(define_insn "*cirrus_cmpsi_1"
-  [(set (reg:CC CC_REGNUM)
-       (compare:CC (match_operand:SI 0 "cirrus_fp_register" "v")
-                   (match_operand:SI 1 "cirrus_fp_register" "v")))]
-  "TARGET_ARM && TARGET_CIRRUS && 0"
-  "cfcmp32%?\\tr15, %V0, %V1"
-  [(set_attr "cirrus_type" "farith")
-   (set_attr "cirrus" "compare")]
-)
-
-(define_insn "*cmpsf_trap"
-  [(set (reg:CCFPE CC_REGNUM)
-       (compare:CCFPE (match_operand:SF 0 "s_register_operand" "f,f")
-                      (match_operand:SF 1 "fpu_add_operand" "fG,H")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "@
-   cmf%?e\\t%0, %1
-   cnf%?e\\t%0, #%N1"
-  [(set_attr "conds" "set")
-   (set_attr "type" "f_2_r")]
-)
-
-(define_insn "*cmpdf_trap"
-  [(set (reg:CCFPE CC_REGNUM)
-       (compare:CCFPE (match_operand:DF 0 "s_register_operand" "f,f")
-                      (match_operand:DF 1 "fpu_add_operand" "fG,H")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "@
-   cmf%?e\\t%0, %1
-   cnf%?e\\t%0, #%N1"
-  [(set_attr "conds" "set")
-   (set_attr "type" "f_2_r")]
-)
-
-(define_insn "*cmp_esfdf_df_trap"
-  [(set (reg:CCFPE CC_REGNUM)
-       (compare:CCFPE (float_extend:DF
-                       (match_operand:SF 0 "s_register_operand" "f,f"))
-                      (match_operand:DF 1 "fpu_add_operand" "fG,H")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "@
-   cmf%?e\\t%0, %1
-   cnf%?e\\t%0, #%N1"
-  [(set_attr "conds" "set")
-   (set_attr "type" "f_2_r")]
-)
+  "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
+  "{
+     arm_compare_op0 = operands[0];
+     arm_compare_op1 = operands[1];
+     DONE;
+   }")
 
-(define_insn "*cmp_df_esfdf_trap"
-  [(set (reg:CCFPE CC_REGNUM)
-       (compare:CCFPE (match_operand:DF 0 "s_register_operand" "f")
-                      (float_extend:DF
-                       (match_operand:SF 1 "s_register_operand" "f"))))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "cmf%?e\\t%0, %1"
-  [(set_attr "conds" "set")
-   (set_attr "type" "f_2_r")]
+(define_insn "*cirrus_cmpdi"
+  [(set (reg:CC CC_REGNUM)
+       (compare:CC (match_operand:DI 0 "cirrus_fp_register" "v")
+                   (match_operand:DI 1 "cirrus_fp_register" "v")))]
+  "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
+  "cfcmp64%?\\tr15, %V0, %V1"
+  [(set_attr "type"   "mav_farith")
+   (set_attr "cirrus" "compare")]
 )
 
 ; This insn allows redundant compares to be removed by cse, nothing should
        (if_then_else (unordered (match_dup 1) (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
   "operands[1] = arm_gen_compare_reg (UNORDERED, arm_compare_op0,
                                      arm_compare_op1);"
 )
        (if_then_else (ordered (match_dup 1) (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
   "operands[1] = arm_gen_compare_reg (ORDERED, arm_compare_op0,
                                      arm_compare_op1);"
 )
        (if_then_else (ungt (match_dup 1) (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
   "operands[1] = arm_gen_compare_reg (UNGT, arm_compare_op0, arm_compare_op1);"
 )
 
        (if_then_else (unlt (match_dup 1) (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
   "operands[1] = arm_gen_compare_reg (UNLT, arm_compare_op0, arm_compare_op1);"
 )
 
        (if_then_else (unge (match_dup 1) (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
   "operands[1] = arm_gen_compare_reg (UNGE, arm_compare_op0, arm_compare_op1);"
 )
 
        (if_then_else (unle (match_dup 1) (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
   "operands[1] = arm_gen_compare_reg (UNLE, arm_compare_op0, arm_compare_op1);"
 )
 
        (if_then_else (uneq (match_dup 1) (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
   "operands[1] = arm_gen_compare_reg (UNEQ, arm_compare_op0, arm_compare_op1);"
 )
 
        (if_then_else (ltgt (match_dup 1) (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
   "operands[1] = arm_gen_compare_reg (LTGT, arm_compare_op0, arm_compare_op1);"
 )
 
        (if_then_else (uneq (match_operand 1 "cc_register" "") (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
   "*
-  if (arm_ccfsm_state != 0)
-    abort ();
+  gcc_assert (!arm_ccfsm_state);
 
   return \"bvs\\t%l0\;beq\\t%l0\";
   "
        (if_then_else (ltgt (match_operand 1 "cc_register" "") (const_int 0))
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
   "*
-  if (arm_ccfsm_state != 0)
-    abort ();
+  gcc_assert (!arm_ccfsm_state);
 
   return \"bmi\\t%l0\;bgt\\t%l0\";
   "
     }
   return \"b%d1\\t%l0\";
   "
-  [(set_attr "conds" "use")]
+  [(set_attr "conds" "use")
+   (set_attr "type" "branch")]
 )
 
 ; Special pattern to match reversed UNEQ.
        (if_then_else (uneq (match_operand 1 "cc_register" "") (const_int 0))
                      (pc)
                      (label_ref (match_operand 0 "" ""))))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
   "*
-  if (arm_ccfsm_state != 0)
-    abort ();
+  gcc_assert (!arm_ccfsm_state);
 
   return \"bmi\\t%l0\;bgt\\t%l0\";
   "
        (if_then_else (ltgt (match_operand 1 "cc_register" "") (const_int 0))
                      (pc)
                      (label_ref (match_operand 0 "" ""))))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
   "*
-  if (arm_ccfsm_state != 0)
-    abort ();
+  gcc_assert (!arm_ccfsm_state);
 
   return \"bvs\\t%l0\;beq\\t%l0\";
   "
     }
   return \"b%D1\\t%l0\";
   "
-  [(set_attr "conds" "use")]
+  [(set_attr "conds" "use")
+   (set_attr "type" "branch")]
 )
 
 \f
 ; scc insns
 
 (define_expand "seq"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+  [(set (match_operand:SI 0 "s_register_operand" "")
        (eq:SI (match_dup 1) (const_int 0)))]
   "TARGET_ARM"
   "operands[1] = arm_gen_compare_reg (EQ, arm_compare_op0, arm_compare_op1);"
 )
 
 (define_expand "sne"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+  [(set (match_operand:SI 0 "s_register_operand" "")
        (ne:SI (match_dup 1) (const_int 0)))]
   "TARGET_ARM"
   "operands[1] = arm_gen_compare_reg (NE, arm_compare_op0, arm_compare_op1);"
 )
 
 (define_expand "sgt"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+  [(set (match_operand:SI 0 "s_register_operand" "")
        (gt:SI (match_dup 1) (const_int 0)))]
   "TARGET_ARM"
   "operands[1] = arm_gen_compare_reg (GT, arm_compare_op0, arm_compare_op1);"
 )
 
 (define_expand "sle"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+  [(set (match_operand:SI 0 "s_register_operand" "")
        (le:SI (match_dup 1) (const_int 0)))]
   "TARGET_ARM"
   "operands[1] = arm_gen_compare_reg (LE, arm_compare_op0, arm_compare_op1);"
 )
 
 (define_expand "sge"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+  [(set (match_operand:SI 0 "s_register_operand" "")
        (ge:SI (match_dup 1) (const_int 0)))]
   "TARGET_ARM"
   "operands[1] = arm_gen_compare_reg (GE, arm_compare_op0, arm_compare_op1);"
 )
 
 (define_expand "slt"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+  [(set (match_operand:SI 0 "s_register_operand" "")
        (lt:SI (match_dup 1) (const_int 0)))]
   "TARGET_ARM"
   "operands[1] = arm_gen_compare_reg (LT, arm_compare_op0, arm_compare_op1);"
 )
 
 (define_expand "sgtu"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+  [(set (match_operand:SI 0 "s_register_operand" "")
        (gtu:SI (match_dup 1) (const_int 0)))]
   "TARGET_ARM"
   "operands[1] = arm_gen_compare_reg (GTU, arm_compare_op0, arm_compare_op1);"
 )
 
 (define_expand "sleu"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+  [(set (match_operand:SI 0 "s_register_operand" "")
        (leu:SI (match_dup 1) (const_int 0)))]
   "TARGET_ARM"
   "operands[1] = arm_gen_compare_reg (LEU, arm_compare_op0, arm_compare_op1);"
 )
 
 (define_expand "sgeu"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+  [(set (match_operand:SI 0 "s_register_operand" "")
        (geu:SI (match_dup 1) (const_int 0)))]
   "TARGET_ARM"
   "operands[1] = arm_gen_compare_reg (GEU, arm_compare_op0, arm_compare_op1);"
 )
 
 (define_expand "sltu"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+  [(set (match_operand:SI 0 "s_register_operand" "")
        (ltu:SI (match_dup 1) (const_int 0)))]
   "TARGET_ARM"
   "operands[1] = arm_gen_compare_reg (LTU, arm_compare_op0, arm_compare_op1);"
 )
 
 (define_expand "sunordered"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+  [(set (match_operand:SI 0 "s_register_operand" "")
        (unordered:SI (match_dup 1) (const_int 0)))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
   "operands[1] = arm_gen_compare_reg (UNORDERED, arm_compare_op0,
                                      arm_compare_op1);"
 )
 
 (define_expand "sordered"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+  [(set (match_operand:SI 0 "s_register_operand" "")
        (ordered:SI (match_dup 1) (const_int 0)))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
   "operands[1] = arm_gen_compare_reg (ORDERED, arm_compare_op0,
                                      arm_compare_op1);"
 )
 
 (define_expand "sungt"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+  [(set (match_operand:SI 0 "s_register_operand" "")
        (ungt:SI (match_dup 1) (const_int 0)))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
   "operands[1] = arm_gen_compare_reg (UNGT, arm_compare_op0,
                                      arm_compare_op1);"
 )
 
 (define_expand "sunge"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+  [(set (match_operand:SI 0 "s_register_operand" "")
        (unge:SI (match_dup 1) (const_int 0)))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
   "operands[1] = arm_gen_compare_reg (UNGE, arm_compare_op0,
                                      arm_compare_op1);"
 )
 
 (define_expand "sunlt"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+  [(set (match_operand:SI 0 "s_register_operand" "")
        (unlt:SI (match_dup 1) (const_int 0)))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
   "operands[1] = arm_gen_compare_reg (UNLT, arm_compare_op0,
                                      arm_compare_op1);"
 )
 
 (define_expand "sunle"
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
+  [(set (match_operand:SI 0 "s_register_operand" "")
        (unle:SI (match_dup 1) (const_int 0)))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
   "operands[1] = arm_gen_compare_reg (UNLE, arm_compare_op0,
                                      arm_compare_op1);"
 )
 ;;; simple ARM instructions. 
 ;
 ; (define_expand "suneq"
-;   [(set (match_operand:SI 0 "s_register_operand" "=r")
+;   [(set (match_operand:SI 0 "s_register_operand" "")
 ;      (uneq:SI (match_dup 1) (const_int 0)))]
-;   "TARGET_ARM && TARGET_HARD_FLOAT"
-;   "abort ();"
+;   "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
+;   "gcc_unreachable ();"
 ; )
 ;
 ; (define_expand "sltgt"
-;   [(set (match_operand:SI 0 "s_register_operand" "=r")
+;   [(set (match_operand:SI 0 "s_register_operand" "")
 ;      (ltgt:SI (match_dup 1) (const_int 0)))]
-;   "TARGET_ARM && TARGET_HARD_FLOAT"
-;   "abort ();"
+;   "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
+;   "gcc_unreachable ();"
 ; )
 
 (define_insn "*mov_scc"
       FAIL;
 
     ccreg = arm_gen_compare_reg (code, arm_compare_op0, arm_compare_op1);
-    operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx);
+    operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx);
   }"
 )
 
 
     /* When compiling for SOFT_FLOAT, ensure both arms are in registers. 
        Otherwise, ensure it is a valid FP add operand */
-    if ((!TARGET_HARD_FLOAT)
-        || (!fpu_add_operand (operands[3], SFmode)))
+    if ((!(TARGET_HARD_FLOAT && TARGET_FPA))
+        || (!arm_float_add_operand (operands[3], SFmode)))
       operands[3] = force_reg (SFmode, operands[3]);
 
     ccreg = arm_gen_compare_reg (code, arm_compare_op0, arm_compare_op1);
-    operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx);
+    operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx);
   }"
 )
 
   [(set (match_operand:DF 0 "s_register_operand" "")
        (if_then_else:DF (match_operand 1 "arm_comparison_operator" "")
                         (match_operand:DF 2 "s_register_operand" "")
-                        (match_operand:DF 3 "fpu_add_operand" "")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
+                        (match_operand:DF 3 "arm_float_add_operand" "")))]
+  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
   "
   {
     enum rtx_code code = GET_CODE (operands[1]);
       FAIL;
 
     ccreg = arm_gen_compare_reg (code, arm_compare_op0, arm_compare_op1);
-    operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx);
+    operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx);
   }"
 )
 
    (set_attr "conds" "use")]
 )
 
-(define_insn "*movsfcc_hard_insn"
-  [(set (match_operand:SF 0 "s_register_operand" "=f,f,f,f,f,f,f,f")
-       (if_then_else:SF
-        (match_operator 3 "arm_comparison_operator" 
-         [(match_operand 4 "cc_register" "") (const_int 0)])
-        (match_operand:SF 1 "fpu_add_operand" "0,0,fG,H,fG,fG,H,H")
-        (match_operand:SF 2 "fpu_add_operand" "fG,H,0,0,fG,H,fG,H")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "@
-   mvf%D3s\\t%0, %2
-   mnf%D3s\\t%0, #%N2
-   mvf%d3s\\t%0, %1
-   mnf%d3s\\t%0, #%N1
-   mvf%d3s\\t%0, %1\;mvf%D3s\\t%0, %2
-   mvf%d3s\\t%0, %1\;mnf%D3s\\t%0, #%N2
-   mnf%d3s\\t%0, #%N1\;mvf%D3s\\t%0, %2
-   mnf%d3s\\t%0, #%N1\;mnf%D3s\\t%0, #%N2"
-  [(set_attr "length" "4,4,4,4,8,8,8,8")
-   (set_attr "type" "ffarith")
-   (set_attr "conds" "use")]
-)
-
 (define_insn "*movsfcc_soft_insn"
   [(set (match_operand:SF 0 "s_register_operand" "=r,r")
        (if_then_else:SF (match_operator 3 "arm_comparison_operator"
   [(set_attr "conds" "use")]
 )
 
-(define_insn "*movdfcc_insn"
-  [(set (match_operand:DF 0 "s_register_operand" "=f,f,f,f,f,f,f,f")
-       (if_then_else:DF
-        (match_operator 3 "arm_comparison_operator"
-         [(match_operand 4 "cc_register" "") (const_int 0)])
-        (match_operand:DF 1 "fpu_add_operand" "0,0,fG,H,fG,fG,H,H")
-        (match_operand:DF 2 "fpu_add_operand" "fG,H,0,0,fG,H,fG,H")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
-  "@
-   mvf%D3d\\t%0, %2
-   mnf%D3d\\t%0, #%N2
-   mvf%d3d\\t%0, %1
-   mnf%d3d\\t%0, #%N1
-   mvf%d3d\\t%0, %1\;mvf%D3d\\t%0, %2
-   mvf%d3d\\t%0, %1\;mnf%D3d\\t%0, #%N2
-   mnf%d3d\\t%0, #%N1\;mvf%D3d\\t%0, %2
-   mnf%d3d\\t%0, #%N1\;mnf%D3d\\t%0, #%N2"
-  [(set_attr "length" "4,4,4,4,8,8,8,8")
-   (set_attr "type" "ffarith")
-   (set_attr "conds" "use")]
-)
-
 \f
 ;; Jump and linkage insns
 
            (const_string "no")))
    (set (attr "length") 
         (if_then_else
-           (and (ge (minus (match_dup 0) (pc)) (const_int -2048))
-                (le (minus (match_dup 0) (pc)) (const_int 2044)))
+           (and (ge (minus (match_dup 0) (pc)) (const_int -2044))
+                (le (minus (match_dup 0) (pc)) (const_int 2048)))
            (const_int 2)
            (const_int 4)))]
 )
   }"
 )
 
-(define_insn "*call_reg"
+(define_insn "*call_reg_armv5"
   [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r"))
          (match_operand 1 "" ""))
    (use (match_operand 2 "" ""))
    (clobber (reg:SI LR_REGNUM))]
-  "TARGET_ARM"
+  "TARGET_ARM && arm_arch5"
+  "blx%?\\t%0"
+  [(set_attr "type" "call")]
+)
+
+(define_insn "*call_reg_arm"
+  [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r"))
+         (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (clobber (reg:SI LR_REGNUM))]
+  "TARGET_ARM && !arm_arch5"
   "*
   return output_call (operands);
   "
    (set_attr "type" "call")]
 )
 
-(define_insn "*call_indirect"
+(define_insn "*call_reg_thumb_v5"
   [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
         (match_operand 1 "" ""))
    (use (match_operand 2 "" ""))
    (clobber (reg:SI LR_REGNUM))]
-  "TARGET_THUMB"
-  "*
-  {
-    if (TARGET_CALLER_INTERWORKING)
-      return \"bl\\t%__interwork_call_via_%0\";
-    else
-      return \"bl\\t%__call_via_%0\";
-  }"
-  [(set_attr "type" "call")]
+  "TARGET_THUMB && arm_arch5"
+  "blx\\t%0"
+  [(set_attr "length" "2")
+   (set_attr "type" "call")]
 )
 
-(define_insn "*call_value_indirect"
-  [(set (match_operand 0 "" "=l")
-       (call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
-             (match_operand 2 "" "")))
-   (use (match_operand 3 "" ""))
+(define_insn "*call_reg_thumb"
+  [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
+        (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
    (clobber (reg:SI LR_REGNUM))]
-  "TARGET_THUMB"
+  "TARGET_THUMB && !arm_arch5"
   "*
   {
-    if (TARGET_CALLER_INTERWORKING)
-      return \"bl\\t%__interwork_call_via_%1\";
+    if (!TARGET_CALLER_INTERWORKING)
+      return thumb_call_via_reg (operands[0]);
+    else if (operands[1] == const0_rtx)
+      return \"bl\\t%__interwork_call_via_%0\";
+    else if (frame_pointer_needed)
+      return \"bl\\t%__interwork_r7_call_via_%0\";
     else
-      return \"bl\\t%__call_via_%1\";
+      return \"bl\\t%__interwork_r11_call_via_%0\";
   }"
   [(set_attr "type" "call")]
 )
   }"
 )
 
-(define_insn "*call_value_reg"
-  [(set (match_operand 0 "" "=r,f,v")
-        (call (mem:SI (match_operand:SI 1 "s_register_operand" "r,r,r"))
+(define_insn "*call_value_reg_armv5"
+  [(set (match_operand 0 "" "")
+        (call (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
              (match_operand 2 "" "")))
    (use (match_operand 3 "" ""))
    (clobber (reg:SI LR_REGNUM))]
-  "TARGET_ARM"
+  "TARGET_ARM && arm_arch5"
+  "blx%?\\t%1"
+  [(set_attr "type" "call")]
+)
+
+(define_insn "*call_value_reg_arm"
+  [(set (match_operand 0 "" "")
+        (call (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
+             (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (clobber (reg:SI LR_REGNUM))]
+  "TARGET_ARM && !arm_arch5"
   "*
   return output_call (&operands[1]);
   "
 )
 
 (define_insn "*call_value_mem"
-  [(set (match_operand 0 "" "=r,f,v")
-       (call (mem:SI (match_operand:SI 1 "memory_operand" "m,m,m"))
+  [(set (match_operand 0 "" "")
+       (call (mem:SI (match_operand:SI 1 "memory_operand" "m"))
              (match_operand 2 "" "")))
    (use (match_operand 3 "" ""))
    (clobber (reg:SI LR_REGNUM))]
    (set_attr "type" "call")]
 )
 
+(define_insn "*call_value_reg_thumb_v5"
+  [(set (match_operand 0 "" "")
+       (call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
+             (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (clobber (reg:SI LR_REGNUM))]
+  "TARGET_THUMB && arm_arch5"
+  "blx\\t%1"
+  [(set_attr "length" "2")
+   (set_attr "type" "call")]
+)
+
+(define_insn "*call_value_reg_thumb"
+  [(set (match_operand 0 "" "")
+       (call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
+             (match_operand 2 "" "")))
+   (use (match_operand 3 "" ""))
+   (clobber (reg:SI LR_REGNUM))]
+  "TARGET_THUMB && !arm_arch5"
+  "*
+  {
+    if (!TARGET_CALLER_INTERWORKING)
+      return thumb_call_via_reg (operands[1]);
+    else if (operands[2] == const0_rtx)
+      return \"bl\\t%__interwork_call_via_%1\";
+    else if (frame_pointer_needed)
+      return \"bl\\t%__interwork_r7_call_via_%1\";
+    else
+      return \"bl\\t%__interwork_r11_call_via_%1\";
+  }"
+  [(set_attr "type" "call")]
+)
+
 ;; Allow calls to SYMBOL_REFs specially as they are not valid general addresses
 ;; The 'a' causes the operand to be treated as an address, i.e. no '#' output.
 
 (define_insn "*call_symbol"
-  [(call (mem:SI (match_operand:SI 0 "" "X"))
+  [(call (mem:SI (match_operand:SI 0 "" ""))
         (match_operand 1 "" ""))
    (use (match_operand 2 "" ""))
    (clobber (reg:SI LR_REGNUM))]
 )
 
 (define_insn "*call_value_symbol"
-  [(set (match_operand 0 "s_register_operand" "=r,f,v")
-       (call (mem:SI (match_operand:SI 1 "" "X,X,X"))
+  [(set (match_operand 0 "" "")
+       (call (mem:SI (match_operand:SI 1 "" ""))
        (match_operand:SI 2 "" "")))
    (use (match_operand 3 "" ""))
    (clobber (reg:SI LR_REGNUM))]
 )
 
 (define_insn "*call_insn"
-  [(call (mem:SI (match_operand:SI 0 "" "X"))
+  [(call (mem:SI (match_operand:SI 0 "" ""))
         (match_operand:SI 1 "" ""))
    (use (match_operand 2 "" ""))
    (clobber (reg:SI LR_REGNUM))]
 )
 
 (define_insn "*call_value_insn"
-  [(set (match_operand 0 "register_operand" "=l")
-       (call (mem:SI (match_operand 1 "" "X"))
+  [(set (match_operand 0 "" "")
+       (call (mem:SI (match_operand 1 "" ""))
              (match_operand 2 "" "")))
    (use (match_operand 3 "" ""))
    (clobber (reg:SI LR_REGNUM))]
 )
 
 (define_expand "sibcall_value"
-  [(parallel [(set (match_operand 0 "register_operand" "")
+  [(parallel [(set (match_operand 0 "" "")
                   (call (match_operand 1 "memory_operand" "")
                         (match_operand 2 "general_operand" "")))
              (return)
 )
 
 (define_insn "*sibcall_value_insn"
- [(set (match_operand 0 "s_register_operand" "=r,f,v")
-       (call (mem:SI (match_operand:SI 1 "" "X,X,X"))
+ [(set (match_operand 0 "" "")
+       (call (mem:SI (match_operand:SI 1 "" "X"))
             (match_operand 2 "" "")))
   (return)
   (use (match_operand 3 "" ""))]
       }
     return output_return_instruction (const_true_rtx, TRUE, FALSE);
   }"
-  [(set_attr "type" "load")
+  [(set_attr "type" "load1")
+   (set_attr "length" "12")
    (set_attr "predicable" "yes")]
 )
 
     return output_return_instruction (operands[0], TRUE, FALSE);
   }"
   [(set_attr "conds" "use")
-   (set_attr "type" "load")]
+   (set_attr "length" "12")
+   (set_attr "type" "load1")]
 )
 
 (define_insn "*cond_return_inverted"
     return output_return_instruction (operands[0], TRUE, TRUE);
   }"
   [(set_attr "conds" "use")
-   (set_attr "type" "load")]
+   (set_attr "length" "12")
+   (set_attr "type" "load1")]
 )
 
 ;; Generate a sequence of instructions to determine if the processor is
                       (const_int 67108860)))] ; 0x03fffffc
   "TARGET_ARM"
   "
-  operands[1] = gen_rtx_REG (CC_NOOVmode, 24);
+  operands[1] = gen_rtx_REG (CC_NOOVmode, CC_REGNUM);
   ")
 
 (define_insn "*check_arch2"
                    (const_int 0))
              (match_operand 1 "" "")
              (match_operand 2 "" "")])]
-  "TARGET_ARM"
+  "TARGET_EITHER"
   "
   {
     int i;
+    rtx par = gen_rtx_PARALLEL (VOIDmode,
+                               rtvec_alloc (XVECLEN (operands[2], 0)));
+    rtx addr = gen_reg_rtx (Pmode);
+    rtx mem;
+    int size = 0;
 
-    emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx));
+    emit_move_insn (addr, XEXP (operands[1], 0));
+    mem = change_address (operands[1], BLKmode, addr);
 
     for (i = 0; i < XVECLEN (operands[2], 0); i++)
       {
-       rtx set = XVECEXP (operands[2], 0, i);
+       rtx src = SET_SRC (XVECEXP (operands[2], 0, i));
+
+       /* Default code only uses r0 as a return value, but we could
+          be using anything up to 4 registers.  */
+       if (REGNO (src) == R0_REGNUM)
+         src = gen_rtx_REG (TImode, R0_REGNUM);
+
+        XVECEXP (par, 0, i) = gen_rtx_EXPR_LIST (VOIDmode, src,
+                                                GEN_INT (size));
+        size += GET_MODE_SIZE (GET_MODE (src));
+      }
+
+    emit_call_insn (GEN_CALL_VALUE (par, operands[0], const0_rtx, NULL,
+                                   const0_rtx));
+
+    size = 0;
+
+    for (i = 0; i < XVECLEN (par, 0); i++)
+      {
+       HOST_WIDE_INT offset = 0;
+       rtx reg = XEXP (XVECEXP (par, 0, i), 0);
+
+       if (size != 0)
+         emit_move_insn (addr, plus_constant (addr, size));
 
-       emit_move_insn (SET_DEST (set), SET_SRC (set));
+       mem = change_address (mem, GET_MODE (reg), NULL);
+       if (REGNO (reg) == R0_REGNUM)
+         {
+           /* On thumb we have to use a write-back instruction.  */
+           emit_insn (arm_gen_store_multiple (R0_REGNUM, 4, addr, TRUE,
+                       TARGET_THUMB ? TRUE : FALSE, mem, &offset));
+           size = TARGET_ARM ? 16 : 0;
+         }
+       else
+         {
+           emit_move_insn (mem, reg);
+           size = GET_MODE_SIZE (GET_MODE (reg));
+         }
       }
 
     /* The optimizer does not know that the call sets the function value
   }"
 )
 
+(define_expand "untyped_return"
+  [(match_operand:BLK 0 "memory_operand" "")
+   (match_operand 1 "" "")]
+  "TARGET_EITHER"
+  "
+  {
+    int i;
+    rtx addr = gen_reg_rtx (Pmode);
+    rtx mem;
+    int size = 0;
+
+    emit_move_insn (addr, XEXP (operands[0], 0));
+    mem = change_address (operands[0], BLKmode, addr);
+
+    for (i = 0; i < XVECLEN (operands[1], 0); i++)
+      {
+       HOST_WIDE_INT offset = 0;
+       rtx reg = SET_DEST (XVECEXP (operands[1], 0, i));
+
+       if (size != 0)
+         emit_move_insn (addr, plus_constant (addr, size));
+
+       mem = change_address (mem, GET_MODE (reg), NULL);
+       if (REGNO (reg) == R0_REGNUM)
+         {
+           /* On thumb we have to use a write-back instruction.  */
+           emit_insn (arm_gen_load_multiple (R0_REGNUM, 4, addr, TRUE,
+                       TARGET_THUMB ? TRUE : FALSE, mem, &offset));
+           size = TARGET_ARM ? 16 : 0;
+         }
+       else
+         {
+           emit_move_insn (reg, mem);
+           size = GET_MODE_SIZE (GET_MODE (reg));
+         }
+      }
+
+    /* Emit USE insns before the return.  */
+    for (i = 0; i < XVECLEN (operands[1], 0); i++)
+      emit_insn (gen_rtx_USE (VOIDmode,
+                             SET_DEST (XVECEXP (operands[1], 0, i))));
+
+    /* Construct the return.  */
+    expand_naked_return ();
+
+    DONE;
+  }"
+)
+
 ;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
 ;; all of memory.  This blocks insns from being moved across this point.
 
   ""
 )
 
+;; NB Never uses BX.
 (define_insn "*arm_indirect_jump"
   [(set (pc)
        (match_operand:SI 0 "s_register_operand" "r"))]
   [(set_attr "predicable" "yes")]
 )
 
-;; Although not supported by the define_expand above,
-;; cse/combine may generate this form.
 (define_insn "*load_indirect_jump"
   [(set (pc)
        (match_operand:SI 0 "memory_operand" "m"))]
   "TARGET_ARM"
   "ldr%?\\t%|pc, %0\\t%@ indirect memory jump"
-  [(set_attr "type" "load")
+  [(set_attr "type" "load1")
    (set_attr "pool_range" "4096")
    (set_attr "neg_pool_range" "4084")
    (set_attr "predicable" "yes")]
 )
 
+;; NB Never uses BX.
 (define_insn "*thumb_indirect_jump"
   [(set (pc)
        (match_operand:SI 0 "register_operand" "l*r"))]
   "%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")))]
 )
 
+(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 "reg_or_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_ARM"
+  [(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 "*arith_shiftsi_compare0"
   [(set (reg:CC_NOOV CC_REGNUM)
         (compare:CC_NOOV (match_operator:SI 1 "shiftable_operator"
   "%i1%?s\\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")))]
 )
 
 (define_insn "*arith_shiftsi_compare0_scratch"
   "%i1%?s\\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")))]
 )
 
 (define_insn "*sub_shiftsi"
   "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")))]
 )
 
 (define_insn "*sub_shiftsi_compare0"
   "TARGET_ARM"
   "sub%?s\\t%0, %1, %3%S2"
   [(set_attr "conds" "set")
-   (set_attr "shift" "3") 
-   ]
+   (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")))]
 )
 
 (define_insn "*sub_shiftsi_compare0_scratch"
   "TARGET_ARM"
   "sub%?s\\t%0, %1, %3%S2"
   [(set_attr "conds" "set")
-   (set_attr "shift" "3") 
-   ]
+   (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")))]
 )
 
 \f
    (clobber (reg:CC CC_REGNUM))]
   "TARGET_ARM"
   "*
-    if (GET_CODE (operands[1]) == LT && operands[3] == const0_rtx)
-      return \"mov\\t%0, %2, lsr #31\";
+    if (operands[3] == const0_rtx)
+      {
+       if (GET_CODE (operands[1]) == LT)
+         return \"mov\\t%0, %2, lsr #31\";
+
+       if (GET_CODE (operands[1]) == GE)
+         return \"mvn\\t%0, %2\;mov\\t%0, %0, lsr #31\";
 
-    if (GET_CODE (operands[1]) == GE && operands[3] == const0_rtx)
-      return \"mvn\\t%0, %2\;mov\\t%0, %0, lsr #31\";
+       if (GET_CODE (operands[1]) == EQ)
+         return \"rsbs\\t%0, %2, #1\;movcc\\t%0, #0\";
+      }
 
     if (GET_CODE (operands[1]) == NE)
       {
   int swap =
     comparison_dominates_p (GET_CODE (operands[5]), GET_CODE (operands[4]));
 
-  return opcodes[which_alternative][swap];
-}
-"
-  [(set_attr "conds" "set")
-   (set_attr "length" "8")]
-)
+  return opcodes[which_alternative][swap];
+}
+"
+  [(set_attr "conds" "set")
+   (set_attr "length" "8")]
+)
+
+(define_insn_and_split "*ior_scc_scc"
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
+       (ior:SI (match_operator:SI 3 "arm_comparison_operator"
+                [(match_operand:SI 1 "s_register_operand" "r")
+                 (match_operand:SI 2 "arm_add_operand" "rIL")])
+               (match_operator:SI 6 "arm_comparison_operator"
+                [(match_operand:SI 4 "s_register_operand" "r")
+                 (match_operand:SI 5 "arm_add_operand" "rIL")])))
+   (clobber (reg:CC CC_REGNUM))]
+  "TARGET_ARM
+   && (arm_select_dominance_cc_mode (operands[3], operands[6], DOM_CC_X_OR_Y)
+       != CCmode)"
+  "#"
+  "TARGET_ARM && reload_completed"
+  [(set (match_dup 7)
+       (compare
+        (ior:SI
+         (match_op_dup 3 [(match_dup 1) (match_dup 2)])
+         (match_op_dup 6 [(match_dup 4) (match_dup 5)]))
+        (const_int 0)))
+   (set (match_dup 0) (ne:SI (match_dup 7) (const_int 0)))]
+  "operands[7]
+     = gen_rtx_REG (arm_select_dominance_cc_mode (operands[3], operands[6],
+                                                 DOM_CC_X_OR_Y),
+                   CC_REGNUM);"
+  [(set_attr "conds" "clob")
+   (set_attr "length" "16")])
+
+; If the above pattern is followed by a CMP insn, then the compare is 
+; redundant, since we can rework the conditional instruction that follows.
+(define_insn_and_split "*ior_scc_scc_cmp"
+  [(set (match_operand 0 "dominant_cc_register" "")
+       (compare (ior:SI (match_operator:SI 3 "arm_comparison_operator"
+                         [(match_operand:SI 1 "s_register_operand" "r")
+                          (match_operand:SI 2 "arm_add_operand" "rIL")])
+                        (match_operator:SI 6 "arm_comparison_operator"
+                         [(match_operand:SI 4 "s_register_operand" "r")
+                          (match_operand:SI 5 "arm_add_operand" "rIL")]))
+                (const_int 0)))
+   (set (match_operand:SI 7 "s_register_operand" "=r")
+       (ior:SI (match_op_dup 3 [(match_dup 1) (match_dup 2)])
+               (match_op_dup 6 [(match_dup 4) (match_dup 5)])))]
+  "TARGET_ARM"
+  "#"
+  "TARGET_ARM && reload_completed"
+  [(set (match_dup 0)
+       (compare
+        (ior:SI
+         (match_op_dup 3 [(match_dup 1) (match_dup 2)])
+         (match_op_dup 6 [(match_dup 4) (match_dup 5)]))
+        (const_int 0)))
+   (set (match_dup 7) (ne:SI (match_dup 0) (const_int 0)))]
+  ""
+  [(set_attr "conds" "set")
+   (set_attr "length" "16")])
+
+(define_insn_and_split "*and_scc_scc"
+  [(set (match_operand:SI 0 "s_register_operand" "=r")
+       (and:SI (match_operator:SI 3 "arm_comparison_operator"
+                [(match_operand:SI 1 "s_register_operand" "r")
+                 (match_operand:SI 2 "arm_add_operand" "rIL")])
+               (match_operator:SI 6 "arm_comparison_operator"
+                [(match_operand:SI 4 "s_register_operand" "r")
+                 (match_operand:SI 5 "arm_add_operand" "rIL")])))
+   (clobber (reg:CC CC_REGNUM))]
+  "TARGET_ARM
+   && (arm_select_dominance_cc_mode (operands[3], operands[6], DOM_CC_X_AND_Y)
+       != CCmode)"
+  "#"
+  "TARGET_ARM && reload_completed
+   && (arm_select_dominance_cc_mode (operands[3], operands[6], DOM_CC_X_AND_Y)
+       != CCmode)"
+  [(set (match_dup 7)
+       (compare
+        (and:SI
+         (match_op_dup 3 [(match_dup 1) (match_dup 2)])
+         (match_op_dup 6 [(match_dup 4) (match_dup 5)]))
+        (const_int 0)))
+   (set (match_dup 0) (ne:SI (match_dup 7) (const_int 0)))]
+  "operands[7]
+     = gen_rtx_REG (arm_select_dominance_cc_mode (operands[3], operands[6],
+                                                 DOM_CC_X_AND_Y),
+                   CC_REGNUM);"
+  [(set_attr "conds" "clob")
+   (set_attr "length" "16")])
+
+; If the above pattern is followed by a CMP insn, then the compare is 
+; redundant, since we can rework the conditional instruction that follows.
+(define_insn_and_split "*and_scc_scc_cmp"
+  [(set (match_operand 0 "dominant_cc_register" "")
+       (compare (and:SI (match_operator:SI 3 "arm_comparison_operator"
+                         [(match_operand:SI 1 "s_register_operand" "r")
+                          (match_operand:SI 2 "arm_add_operand" "rIL")])
+                        (match_operator:SI 6 "arm_comparison_operator"
+                         [(match_operand:SI 4 "s_register_operand" "r")
+                          (match_operand:SI 5 "arm_add_operand" "rIL")]))
+                (const_int 0)))
+   (set (match_operand:SI 7 "s_register_operand" "=r")
+       (and:SI (match_op_dup 3 [(match_dup 1) (match_dup 2)])
+               (match_op_dup 6 [(match_dup 4) (match_dup 5)])))]
+  "TARGET_ARM"
+  "#"
+  "TARGET_ARM && reload_completed"
+  [(set (match_dup 0)
+       (compare
+        (and:SI
+         (match_op_dup 3 [(match_dup 1) (match_dup 2)])
+         (match_op_dup 6 [(match_dup 4) (match_dup 5)]))
+        (const_int 0)))
+   (set (match_dup 7) (ne:SI (match_dup 0) (const_int 0)))]
+  ""
+  [(set_attr "conds" "set")
+   (set_attr "length" "16")])
+
+;; If there is no dominance in the comparison, then we can still save an
+;; instruction in the AND case, since we can know that the second compare
+;; need only zero the value if false (if true, then the value is already
+;; correct).
+(define_insn_and_split "*and_scc_scc_nodom"
+  [(set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r")
+       (and:SI (match_operator:SI 3 "arm_comparison_operator"
+                [(match_operand:SI 1 "s_register_operand" "r,r,0")
+                 (match_operand:SI 2 "arm_add_operand" "rIL,0,rIL")])
+               (match_operator:SI 6 "arm_comparison_operator"
+                [(match_operand:SI 4 "s_register_operand" "r,r,r")
+                 (match_operand:SI 5 "arm_add_operand" "rIL,rIL,rIL")])))
+   (clobber (reg:CC CC_REGNUM))]
+  "TARGET_ARM
+   && (arm_select_dominance_cc_mode (operands[3], operands[6], DOM_CC_X_AND_Y)
+       == CCmode)"
+  "#"
+  "TARGET_ARM && reload_completed"
+  [(parallel [(set (match_dup 0)
+                  (match_op_dup 3 [(match_dup 1) (match_dup 2)]))
+             (clobber (reg:CC CC_REGNUM))])
+   (set (match_dup 7) (match_op_dup 8 [(match_dup 4) (match_dup 5)]))
+   (set (match_dup 0)
+       (if_then_else:SI (match_op_dup 6 [(match_dup 7) (const_int 0)])
+                        (match_dup 0)
+                        (const_int 0)))]
+  "operands[7] = gen_rtx_REG (SELECT_CC_MODE (GET_CODE (operands[6]),
+                                             operands[4], operands[5]),
+                             CC_REGNUM);
+   operands[8] = gen_rtx_COMPARE (GET_MODE (operands[7]), operands[4],
+                                 operands[5]);"
+  [(set_attr "conds" "clob")
+   (set_attr "length" "20")])
+
+(define_split
+  [(set (reg:CC_NOOV CC_REGNUM)
+       (compare:CC_NOOV (ior:SI
+                         (and:SI (match_operand:SI 0 "s_register_operand" "")
+                                 (const_int 1))
+                         (match_operator:SI 1 "comparison_operator"
+                          [(match_operand:SI 2 "s_register_operand" "")
+                           (match_operand:SI 3 "arm_add_operand" "")]))
+                        (const_int 0)))
+   (clobber (match_operand:SI 4 "s_register_operand" ""))]
+  "TARGET_ARM"
+  [(set (match_dup 4)
+       (ior:SI (match_op_dup 1 [(match_dup 2) (match_dup 3)])
+               (match_dup 0)))
+   (set (reg:CC_NOOV CC_REGNUM)
+       (compare:CC_NOOV (and:SI (match_dup 4) (const_int 1))
+                        (const_int 0)))]
+  "")
+
+(define_split
+  [(set (reg:CC_NOOV CC_REGNUM)
+       (compare:CC_NOOV (ior:SI
+                         (match_operator:SI 1 "comparison_operator"
+                          [(match_operand:SI 2 "s_register_operand" "")
+                           (match_operand:SI 3 "arm_add_operand" "")])
+                         (and:SI (match_operand:SI 0 "s_register_operand" "")
+                                 (const_int 1)))
+                        (const_int 0)))
+   (clobber (match_operand:SI 4 "s_register_operand" ""))]
+  "TARGET_ARM"
+  [(set (match_dup 4)
+       (ior:SI (match_op_dup 1 [(match_dup 2) (match_dup 3)])
+               (match_dup 0)))
+   (set (reg:CC_NOOV CC_REGNUM)
+       (compare:CC_NOOV (and:SI (match_dup 4) (const_int 1))
+                        (const_int 0)))]
+  "")
 
 (define_insn "*negscc"
   [(set (match_operand:SI 0 "s_register_operand" "=r")
          return \"bics\\t%0, %2, %3, asr #32\;movcs\\t%0, %1\";
        }
       /* The only case that falls through to here is when both ops 1 & 2
-        are constants */
+        are constants */
     }
 
   if (GET_CODE (operands[5]) == GE
          return \"ands\\t%0, %2, %3, asr #32\;movcc\\t%0, %1\";
        }
       /* The only case that falls through to here is when both ops 1 & 2
-        are constants */
+        are constants */
     }
   if (GET_CODE (operands[4]) == CONST_INT
       && !const_ok_for_arm (INTVAL (operands[4])))
   "*
   /* If we have an operation where (op x 0) is the identity operation and
      the conditional operator is LT or GE and we are comparing against zero and
-     everything is in registers then we can do this in two instructions */
+     everything is in registers then we can do this in two instructions */
   if (operands[3] == const0_rtx
       && GET_CODE (operands[7]) != AND
       && GET_CODE (operands[5]) == REG
    mvn%D5\\t%0, #%B1\;mov%d5\\t%0, %2%S4"
   [(set_attr "conds" "use")
    (set_attr "shift" "2")
-   (set_attr "length" "4,8,8")]
+   (set_attr "length" "4,8,8")
+   (set (attr "type") (if_then_else (match_operand 3 "const_int_operand" "")
+                     (const_string "alu_shift")
+                     (const_string "alu_shift_reg")))]
 )
 
 (define_insn "*ifcompare_move_shift"
    mvn%d5\\t%0, #%B1\;mov%D5\\t%0, %2%S4"
   [(set_attr "conds" "use")
    (set_attr "shift" "2")
-   (set_attr "length" "4,8,8")]
+   (set_attr "length" "4,8,8")
+   (set (attr "type") (if_then_else (match_operand 3 "const_int_operand" "")
+                     (const_string "alu_shift")
+                     (const_string "alu_shift_reg")))]
 )
 
 (define_insn "*ifcompare_shift_shift"
   "mov%d5\\t%0, %1%S6\;mov%D5\\t%0, %3%S7"
   [(set_attr "conds" "use")
    (set_attr "shift" "1")
-   (set_attr "length" "8")]
+   (set_attr "length" "8")
+   (set (attr "type") (if_then_else
+                       (and (match_operand 2 "const_int_operand" "")
+                             (match_operand 4 "const_int_operand" ""))
+                     (const_string "alu_shift")
+                     (const_string "alu_shift_reg")))]
 )
 
 (define_insn "*ifcompare_not_arith"
   {
     rtx ldm[3];
     rtx arith[4];
-    int val1 = 0, val2 = 0;
+    rtx base_reg;
+    HOST_WIDE_INT val1 = 0, val2 = 0;
 
     if (REGNO (operands[0]) > REGNO (operands[4]))
       {
        ldm[1] = operands[0];
        ldm[2] = operands[4];
       }
-    if (GET_CODE (XEXP (operands[2], 0)) != REG)
-      val1 = INTVAL (XEXP (XEXP (operands[2], 0), 1));
-    if (GET_CODE (XEXP (operands[3], 0)) != REG)
+
+    base_reg = XEXP (operands[2], 0);
+
+    if (!REG_P (base_reg))
+      {
+       val1 = INTVAL (XEXP (base_reg, 1));
+       base_reg = XEXP (base_reg, 0);
+      }
+
+    if (!REG_P (XEXP (operands[3], 0)))
       val2 = INTVAL (XEXP (XEXP (operands[3], 0), 1));
+
     arith[0] = operands[0];
     arith[3] = operands[1];
+
     if (val1 < val2)
       {
        arith[1] = ldm[1];
        arith[1] = ldm[2];
        arith[2] = ldm[1];
       }
-   if (val1 && val2)
+
+    ldm[0] = base_reg;
+    if (val1 !=0 && val2 != 0)
       {
-       rtx ops[3];
-       ldm[0] = ops[0] = operands[4];
-       ops[1] = XEXP (XEXP (operands[2], 0), 0);
-       ops[2] = XEXP (XEXP (operands[2], 0), 1);
-       output_add_immediate (ops);
-       if (val1 < val2)
-         output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm);
+       if (val1 == 4 || val2 == 4)
+         /* Other val must be 8, since we know they are adjacent and neither
+            is zero.  */
+         output_asm_insn (\"ldm%?ib\\t%0, {%1, %2}\", ldm);
        else
-         output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm);
+         {
+           rtx ops[3];
+
+           ldm[0] = ops[0] = operands[4];
+           ops[1] = base_reg;
+           ops[2] = GEN_INT (val1);
+           output_add_immediate (ops);
+           if (val1 < val2)
+             output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm);
+           else
+             output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm);
+         }
       }
-    else if (val1)
+    else if (val1 != 0)
       {
-       ldm[0] = XEXP (operands[3], 0);
        if (val1 < val2)
          output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm);
        else
       }
     else
       {
-       ldm[0] = XEXP (operands[2], 0);
        if (val1 < val2)
          output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm);
        else
   }"
   [(set_attr "length" "12")
    (set_attr "predicable" "yes")
-   (set_attr "type" "load")]
-)
-
-;; the arm can support extended pre-inc instructions
-
-;; In all these cases, we use operands 0 and 1 for the register being
-;; incremented because those are the operands that local-alloc will
-;; tie and these are the pair most likely to be tieable (and the ones
-;; that will benefit the most).
-
-;; We reject the frame pointer if it occurs anywhere in these patterns since
-;; elimination will cause too many headaches.
-
-(define_insn "*strqi_preinc"
-  [(set (mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
-                        (match_operand:SI 2 "index_operand" "rJ")))
-       (match_operand:QI 3 "s_register_operand" "r"))
-   (set (match_operand:SI 0 "s_register_operand" "=r")
-       (plus:SI (match_dup 1) (match_dup 2)))]
-  "TARGET_ARM
-   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
-   && (GET_CODE (operands[2]) != REG
-       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
-  "str%?b\\t%3, [%0, %2]!"
-  [(set_attr "type" "store1")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*strqi_predec"
-  [(set (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
-                         (match_operand:SI 2 "s_register_operand" "r")))
-       (match_operand:QI 3 "s_register_operand" "r"))
-   (set (match_operand:SI 0 "s_register_operand" "=r")
-       (minus:SI (match_dup 1) (match_dup 2)))]
-  "TARGET_ARM
-   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
-   && (GET_CODE (operands[2]) != REG
-       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
-  "str%?b\\t%3, [%0, -%2]!"
-  [(set_attr "type" "store1")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadqi_preinc"
-  [(set (match_operand:QI 3 "s_register_operand" "=r")
-       (mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
-                        (match_operand:SI 2 "index_operand" "rJ"))))
-   (set (match_operand:SI 0 "s_register_operand" "=r")
-       (plus:SI (match_dup 1) (match_dup 2)))]
-  "TARGET_ARM
-   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
-   && (GET_CODE (operands[2]) != REG
-       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
-  "ldr%?b\\t%3, [%0, %2]!"
-  [(set_attr "type" "load")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadqi_predec"
-  [(set (match_operand:QI 3 "s_register_operand" "=r")
-       (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
-                         (match_operand:SI 2 "s_register_operand" "r"))))
-   (set (match_operand:SI 0 "s_register_operand" "=r")
-       (minus:SI (match_dup 1) (match_dup 2)))]
-  "TARGET_ARM
-   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
-   && (GET_CODE (operands[2]) != REG
-       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
-  "ldr%?b\\t%3, [%0, -%2]!"
-  [(set_attr "type" "load")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadqisi_preinc"
-  [(set (match_operand:SI 3 "s_register_operand" "=r")
-       (zero_extend:SI
-        (mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
-                         (match_operand:SI 2 "index_operand" "rJ")))))
-   (set (match_operand:SI 0 "s_register_operand" "=r")
-       (plus:SI (match_dup 1) (match_dup 2)))]
-  "TARGET_ARM
-   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
-   && (GET_CODE (operands[2]) != REG
-       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
-  "ldr%?b\\t%3, [%0, %2]!\\t%@ z_extendqisi"
-  [(set_attr "type" "load")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadqisi_predec"
-  [(set (match_operand:SI 3 "s_register_operand" "=r")
-       (zero_extend:SI
-        (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
-                          (match_operand:SI 2 "s_register_operand" "r")))))
-   (set (match_operand:SI 0 "s_register_operand" "=r")
-       (minus:SI (match_dup 1) (match_dup 2)))]
-  "TARGET_ARM
-   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
-   && (GET_CODE (operands[2]) != REG
-       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
-  "ldr%?b\\t%3, [%0, -%2]!\\t%@ z_extendqisi"
-  [(set_attr "type" "load")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*strsi_preinc"
-  [(set (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
-                        (match_operand:SI 2 "index_operand" "rJ")))
-       (match_operand:SI 3 "s_register_operand" "r"))
-   (set (match_operand:SI 0 "s_register_operand" "=r")
-       (plus:SI (match_dup 1) (match_dup 2)))]
-  "TARGET_ARM
-   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
-   && (GET_CODE (operands[2]) != REG
-       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
-  "str%?\\t%3, [%0, %2]!"
-  [(set_attr "type" "store1")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*strsi_predec"
-  [(set (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
-                         (match_operand:SI 2 "s_register_operand" "r")))
-       (match_operand:SI 3 "s_register_operand" "r"))
-   (set (match_operand:SI 0 "s_register_operand" "=r")
-       (minus:SI (match_dup 1) (match_dup 2)))]
-  "TARGET_ARM
-   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
-   && (GET_CODE (operands[2]) != REG
-       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
-  "str%?\\t%3, [%0, -%2]!"
-  [(set_attr "type" "store1")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadsi_preinc"
-  [(set (match_operand:SI 3 "s_register_operand" "=r")
-       (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
-                        (match_operand:SI 2 "index_operand" "rJ"))))
-   (set (match_operand:SI 0 "s_register_operand" "=r")
-       (plus:SI (match_dup 1) (match_dup 2)))]
-  "TARGET_ARM
-   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
-   && (GET_CODE (operands[2]) != REG
-       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
-  "ldr%?\\t%3, [%0, %2]!"
-  [(set_attr "type" "load")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadsi_predec"
-  [(set (match_operand:SI 3 "s_register_operand" "=r")
-       (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
-                         (match_operand:SI 2 "s_register_operand" "r"))))
-   (set (match_operand:SI 0 "s_register_operand" "=r")
-       (minus:SI (match_dup 1) (match_dup 2)))]
-  "TARGET_ARM
-   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
-   && (GET_CODE (operands[2]) != REG
-       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
-  "ldr%?\\t%3, [%0, -%2]!"
-  [(set_attr "type" "load")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadhi_preinc"
-  [(set (match_operand:HI 3 "s_register_operand" "=r")
-       (mem:HI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
-                        (match_operand:SI 2 "index_operand" "rJ"))))
-   (set (match_operand:SI 0 "s_register_operand" "=r")
-       (plus:SI (match_dup 1) (match_dup 2)))]
-  "TARGET_ARM
-   && !BYTES_BIG_ENDIAN
-   && !TARGET_MMU_TRAPS
-   && !arm_arch4
-   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
-   && (GET_CODE (operands[2]) != REG
-       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
-  "ldr%?\\t%3, [%0, %2]!\\t%@ loadhi"
-  [(set_attr "type" "load")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadhi_predec"
-  [(set (match_operand:HI 3 "s_register_operand" "=r")
-       (mem:HI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
-                         (match_operand:SI 2 "s_register_operand" "r"))))
-   (set (match_operand:SI 0 "s_register_operand" "=r")
-       (minus:SI (match_dup 1) (match_dup 2)))]
-  "TARGET_ARM
-   && !BYTES_BIG_ENDIAN
-   && !TARGET_MMU_TRAPS
-   && !arm_arch4
-   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
-   && (GET_CODE (operands[2]) != REG
-       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
-  "ldr%?\\t%3, [%0, -%2]!\\t%@ loadhi"
-  [(set_attr "type" "load")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*strqi_shiftpreinc"
-  [(set (mem:QI (plus:SI (match_operator:SI 2 "shift_operator"
-                         [(match_operand:SI 3 "s_register_operand" "r")
-                          (match_operand:SI 4 "const_shift_operand" "n")])
-                        (match_operand:SI 1 "s_register_operand" "0")))
-       (match_operand:QI 5 "s_register_operand" "r"))
-   (set (match_operand:SI 0 "s_register_operand" "=r")
-       (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)])
-                (match_dup 1)))]
-  "TARGET_ARM
-   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
-  "str%?b\\t%5, [%0, %3%S2]!"
-  [(set_attr "type" "store1")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*strqi_shiftpredec"
-  [(set (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
-                         (match_operator:SI 2 "shift_operator"
-                          [(match_operand:SI 3 "s_register_operand" "r")
-                           (match_operand:SI 4 "const_shift_operand" "n")])))
-       (match_operand:QI 5 "s_register_operand" "r"))
-   (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
-   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
-  "str%?b\\t%5, [%0, -%3%S2]!"
-  [(set_attr "type" "store1")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadqi_shiftpreinc"
-  [(set (match_operand:QI 5 "s_register_operand" "=r")
-       (mem:QI (plus:SI (match_operator:SI 2 "shift_operator"
-                         [(match_operand:SI 3 "s_register_operand" "r")
-                          (match_operand:SI 4 "const_shift_operand" "n")])
-                        (match_operand:SI 1 "s_register_operand" "0"))))
-   (set (match_operand:SI 0 "s_register_operand" "=r")
-       (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)])
-                (match_dup 1)))]
-  "TARGET_ARM
-   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
-  "ldr%?b\\t%5, [%0, %3%S2]!"
-  [(set_attr "type" "load")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadqi_shiftpredec"
-  [(set (match_operand:QI 5 "s_register_operand" "=r")
-       (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
-                         (match_operator:SI 2 "shift_operator"
-                          [(match_operand:SI 3 "s_register_operand" "r")
-                           (match_operand:SI 4 "const_shift_operand" "n")]))))
-   (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
-   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
-  "ldr%?b\\t%5, [%0, -%3%S2]!"
-  [(set_attr "type" "load")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*strsi_shiftpreinc"
-  [(set (mem:SI (plus:SI (match_operator:SI 2 "shift_operator"
-                         [(match_operand:SI 3 "s_register_operand" "r")
-                          (match_operand:SI 4 "const_shift_operand" "n")])
-                        (match_operand:SI 1 "s_register_operand" "0")))
-       (match_operand:SI 5 "s_register_operand" "r"))
-   (set (match_operand:SI 0 "s_register_operand" "=r")
-       (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)])
-                (match_dup 1)))]
-  "TARGET_ARM
-   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
-  "str%?\\t%5, [%0, %3%S2]!"
-  [(set_attr "type" "store1")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*strsi_shiftpredec"
-  [(set (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
-                         (match_operator:SI 2 "shift_operator"
-                          [(match_operand:SI 3 "s_register_operand" "r")
-                           (match_operand:SI 4 "const_shift_operand" "n")])))
-       (match_operand:SI 5 "s_register_operand" "r"))
-   (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
-   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
-  "str%?\\t%5, [%0, -%3%S2]!"
-  [(set_attr "type" "store1")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadsi_shiftpreinc"
-  [(set (match_operand:SI 5 "s_register_operand" "=r")
-       (mem:SI (plus:SI (match_operator:SI 2 "shift_operator"
-                         [(match_operand:SI 3 "s_register_operand" "r")
-                          (match_operand:SI 4 "const_shift_operand" "n")])
-                        (match_operand:SI 1 "s_register_operand" "0"))))
-   (set (match_operand:SI 0 "s_register_operand" "=r")
-       (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)])
-                (match_dup 1)))]
-  "TARGET_ARM
-   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
-  "ldr%?\\t%5, [%0, %3%S2]!"
-  [(set_attr "type" "load")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadsi_shiftpredec"
-  [(set (match_operand:SI 5 "s_register_operand" "=r")
-       (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
-                         (match_operator:SI 2 "shift_operator"
-                          [(match_operand:SI 3 "s_register_operand" "r")
-                           (match_operand:SI 4 "const_shift_operand" "n")]))))
-   (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
-   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
-  "ldr%?\\t%5, [%0, -%3%S2]!"
-  [(set_attr "type" "load")
-   (set_attr "predicable" "yes")])
-
-(define_insn "*loadhi_shiftpreinc"
-  [(set (match_operand:HI 5 "s_register_operand" "=r")
-       (mem:HI (plus:SI (match_operator:SI 2 "shift_operator"
-                         [(match_operand:SI 3 "s_register_operand" "r")
-                          (match_operand:SI 4 "const_shift_operand" "n")])
-                        (match_operand:SI 1 "s_register_operand" "0"))))
-   (set (match_operand:SI 0 "s_register_operand" "=r")
-       (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)])
-                (match_dup 1)))]
-  "TARGET_ARM
-   && !BYTES_BIG_ENDIAN
-   && !TARGET_MMU_TRAPS
-   && !arm_arch4
-   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
-  "ldr%?\\t%5, [%0, %3%S2]!\\t%@ loadhi"
-  [(set_attr "type" "load")
-   (set_attr "predicable" "yes")]
-)
-
-(define_insn "*loadhi_shiftpredec"
-  [(set (match_operand:HI 5 "s_register_operand" "=r")
-       (mem:HI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
-                         (match_operator:SI 2 "shift_operator"
-                          [(match_operand:SI 3 "s_register_operand" "r")
-                           (match_operand:SI 4 "const_shift_operand" "n")]))))
-   (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
-   && !BYTES_BIG_ENDIAN
-   && !TARGET_MMU_TRAPS
-   && !arm_arch4
-   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
-   && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
-  "ldr%?\\t%5, [%0, -%3%S2]!\\t%@ loadhi"
-  [(set_attr "type" "load")
-   (set_attr "predicable" "yes")]
-)
-
-; It can also support extended post-inc expressions, but combine doesn't
-; try these....
-; It doesn't seem worth adding peepholes for anything but the most common
-; cases since, unlike combine, the increment must immediately follow the load
-; for this pattern to match.
-; We must watch to see that the source/destination register isn't also the
-; same as the base address register, and that if the index is a register,
-; that it is not the same as the base address register.  In such cases the
-; instruction that we would generate would have UNPREDICTABLE behavior so 
-; we cannot use it.
-
-(define_peephole
-  [(set (mem:QI (match_operand:SI 0 "s_register_operand" "+r"))
-       (match_operand:QI 2 "s_register_operand" "r"))
-   (set (match_dup 0)
-       (plus:SI (match_dup 0) (match_operand:SI 1 "index_operand" "rJ")))]
-  "TARGET_ARM
-   && (REGNO (operands[2]) != REGNO (operands[0]))
-   && (GET_CODE (operands[1]) != REG
-       || (REGNO (operands[1]) != REGNO (operands[0])))"
-  "str%?b\\t%2, [%0], %1"
-)
-
-(define_peephole
-  [(set (match_operand:QI 0 "s_register_operand" "=r")
-       (mem:QI (match_operand:SI 1 "s_register_operand" "+r")))
-   (set (match_dup 1)
-       (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))]
-  "TARGET_ARM
-   && REGNO (operands[0]) != REGNO(operands[1])
-   && (GET_CODE (operands[2]) != REG
-       || REGNO(operands[0]) != REGNO (operands[2]))"
-  "ldr%?b\\t%0, [%1], %2"
-)
-
-(define_peephole
-  [(set (mem:SI (match_operand:SI 0 "s_register_operand" "+r"))
-       (match_operand:SI 2 "s_register_operand" "r"))
-   (set (match_dup 0)
-       (plus:SI (match_dup 0) (match_operand:SI 1 "index_operand" "rJ")))]
-  "TARGET_ARM
-   && (REGNO (operands[2]) != REGNO (operands[0]))
-   && (GET_CODE (operands[1]) != REG
-       || (REGNO (operands[1]) != REGNO (operands[0])))"
-  "str%?\\t%2, [%0], %1"
-)
-
-(define_peephole
-  [(set (match_operand:HI 0 "s_register_operand" "=r")
-       (mem:HI (match_operand:SI 1 "s_register_operand" "+r")))
-   (set (match_dup 1)
-       (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))]
-  "TARGET_ARM
-   && !BYTES_BIG_ENDIAN
-   && !TARGET_MMU_TRAPS
-   && !arm_arch4
-   && REGNO (operands[0]) != REGNO(operands[1])
-   && (GET_CODE (operands[2]) != REG
-       || REGNO(operands[0]) != REGNO (operands[2]))"
-  "ldr%?\\t%0, [%1], %2\\t%@ loadhi"
-)
-
-(define_peephole
-  [(set (match_operand:SI 0 "s_register_operand" "=r")
-       (mem:SI (match_operand:SI 1 "s_register_operand" "+r")))
-   (set (match_dup 1)
-       (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))]
-  "TARGET_ARM
-   && REGNO (operands[0]) != REGNO(operands[1])
-   && (GET_CODE (operands[2]) != REG
-       || REGNO(operands[0]) != REGNO (operands[2]))"
-  "ldr%?\\t%0, [%1], %2"
-)
-
-(define_peephole
-  [(set (mem:QI (plus:SI (match_operand:SI 0 "s_register_operand" "+r")
-                        (match_operand:SI 1 "index_operand" "rJ")))
-       (match_operand:QI 2 "s_register_operand" "r"))
-   (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))]
-  "TARGET_ARM
-   && (REGNO (operands[2]) != REGNO (operands[0]))
-   && (GET_CODE (operands[1]) != REG
-       || (REGNO (operands[1]) != REGNO (operands[0])))"
-  "str%?b\\t%2, [%0, %1]!"
-)
-
-(define_peephole
-  [(set (mem:QI (plus:SI (match_operator:SI 4 "shift_operator"
-                         [(match_operand:SI 0 "s_register_operand" "r")
-                          (match_operand:SI 1 "const_int_operand" "n")])
-                        (match_operand:SI 2 "s_register_operand" "+r")))
-       (match_operand:QI 3 "s_register_operand" "r"))
-   (set (match_dup 2) (plus:SI (match_op_dup 4 [(match_dup 0) (match_dup 1)])
-                              (match_dup 2)))]
-  "TARGET_ARM
-   && (REGNO (operands[3]) != REGNO (operands[2]))
-   && (REGNO (operands[0]) != REGNO (operands[2]))"
-  "str%?b\\t%3, [%2, %0%S4]!"
+   (set_attr "type" "load1")]
 )
 
 ; This pattern is never tried by combine, so do it as a peephole
 
 (define_peephole2
-  [(set (match_operand:SI 0 "s_register_operand" "")
-       (match_operand:SI 1 "s_register_operand" ""))
+  [(set (match_operand:SI 0 "arm_general_register_operand" "")
+       (match_operand:SI 1 "arm_general_register_operand" ""))
    (set (reg:CC CC_REGNUM)
        (compare:CC (match_dup 1) (const_int 0)))]
-  "TARGET_ARM
-   && (!TARGET_CIRRUS
-       || (!cirrus_fp_register (operands[0], SImode)
-           && !cirrus_fp_register (operands[1], SImode)))
-  "
+  "TARGET_ARM"
   [(parallel [(set (reg:CC CC_REGNUM) (compare:CC (match_dup 1) (const_int 0)))
              (set (match_dup 0) (match_dup 1))])]
   ""
 )
 
 (define_expand "epilogue"
-  [(unspec_volatile [(return)] VUNSPEC_EPILOGUE)]
+  [(clobber (const_int 0))]
   "TARGET_EITHER"
   "
+  if (current_function_calls_eh_return)
+    emit_insn (gen_prologue_use (gen_rtx_REG (Pmode, 2)));
   if (TARGET_THUMB)
     thumb_expand_epilogue ();
   else if (USE_RETURN_INSN (FALSE))
               (unspec_volatile [(return)] VUNSPEC_EPILOGUE)])]
   "TARGET_ARM"
   "*
-  if (USE_RETURN_INSN (FALSE))
+  if (use_return_insn (FALSE, next_nonnote_insn (insn)))
     return output_return_instruction (const_true_rtx, FALSE, FALSE);
-  return arm_output_epilogue (FALSE);
+  return arm_output_epilogue (next_nonnote_insn (insn));
   "
 ;; Length is absolute worst case
   [(set_attr "length" "44")
   "TARGET_EITHER"
   "*
   if (TARGET_ARM)
-    return arm_output_epilogue (TRUE);
+    return arm_output_epilogue (NULL);
   else /* TARGET_THUMB */
     return thumb_unexpanded_epilogue ();
   "
 )
 
 (define_expand "eh_epilogue"
-  [(use (match_operand:SI 0 "register_operand" "r"))
-   (use (match_operand:SI 1 "register_operand" "r"))
-   (use (match_operand:SI 2 "register_operand" "r"))]
+  [(use (match_operand:SI 0 "register_operand" ""))
+   (use (match_operand:SI 1 "register_operand" ""))
+   (use (match_operand:SI 2 "register_operand" ""))]
   "TARGET_EITHER"
   "
   {
     enum rtx_code rc = GET_CODE (operands[1]);
 
     operands[6] = gen_rtx_REG (mode, CC_REGNUM);
-    operands[7] = gen_rtx (COMPARE, mode, operands[2], operands[3]);
+    operands[7] = gen_rtx_COMPARE (mode, operands[2], operands[3]);
     if (mode == CCFPmode || mode == CCFPEmode)
       rc = reverse_condition_maybe_unordered (rc);
     else
     [(set (match_operand:BLK 0 "memory_operand" "=m")
          (unspec:BLK [(match_operand:XF 1 "f_register_operand" "f")]
                      UNSPEC_PUSH_MULT))])]
-  "TARGET_ARM"
+  "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
   "*
   {
     char pattern[100];
   "
 )
 
+(define_insn "align_8"
+  [(unspec_volatile [(const_int 0)] VUNSPEC_ALIGN8)]
+  "TARGET_EITHER"
+  "*
+  assemble_align (64);
+  return \"\";
+  "
+)
+
 (define_insn "consttable_end"
   [(unspec_volatile [(const_int 0)] VUNSPEC_POOL_END)]
   "TARGET_EITHER"
 ;; Miscellaneous Thumb patterns
 
 (define_expand "tablejump"
-  [(parallel [(set (pc) (match_operand:SI 0 "register_operand" "l*r"))
+  [(parallel [(set (pc) (match_operand:SI 0 "register_operand" ""))
              (use (label_ref (match_operand 1 "" "")))])]
   "TARGET_THUMB"
   "
   "
 )
 
+;; NB never uses BX.
 (define_insn "*thumb_tablejump"
   [(set (pc) (match_operand:SI 0 "register_operand" "l*r"))
    (use (label_ref (match_operand 1 "" "")))]
   [(set (match_operand:SI 0 "s_register_operand" "=r")
        (clz:SI (match_operand:SI 1 "s_register_operand" "r")))]
   "TARGET_ARM && arm_arch5"
-  "clz\\t%0, %1")
+  "clz%?\\t%0, %1"
+  [(set_attr "predicable" "yes")])
 
 (define_expand "ffssi2"
   [(set (match_operand:SI 0 "s_register_operand" "")
   ""
   "%@ %0 needed for prologue"
 )
+
+
+;; Patterns for exception handling
+
+(define_expand "eh_return"
+  [(use (match_operand 0 "general_operand" ""))]
+  "TARGET_EITHER"
+  "
+  {
+    if (TARGET_ARM)
+      emit_insn (gen_arm_eh_return (operands[0]));
+    else
+      emit_insn (gen_thumb_eh_return (operands[0]));
+    DONE;
+  }"
+)
+                                  
+;; We can't expand this before we know where the link register is stored.
+(define_insn_and_split "arm_eh_return"
+  [(unspec_volatile [(match_operand:SI 0 "s_register_operand" "r")]
+                   VUNSPEC_EH_RETURN)
+   (clobber (match_scratch:SI 1 "=&r"))]
+  "TARGET_ARM"
+  "#"
+  "&& reload_completed"
+  [(const_int 0)]
+  "
+  {
+    arm_set_return_address (operands[0], operands[1]);
+    DONE;
+  }"
+)
+
+(define_insn_and_split "thumb_eh_return"
+  [(unspec_volatile [(match_operand:SI 0 "s_register_operand" "l")]
+                   VUNSPEC_EH_RETURN)
+   (clobber (match_scratch:SI 1 "=&l"))]
+  "TARGET_THUMB"
+  "#"
+  "&& reload_completed"
+  [(const_int 0)]
+  "
+  {
+    thumb_set_return_address (operands[0], operands[1]);
+    DONE;
+  }"
+)
+
+;; Load the FPA co-processor patterns
+(include "fpa.md")
+;; Load the Maverick co-processor patterns
+(include "cirrus.md")
+;; Load the Intel Wireless Multimedia Extension patterns
+(include "iwmmxt.md")
+;; Load the VFP co-processor patterns
+(include "vfp.md")
+