190075Sobrien;;- Machine description for ARM for GNU compiler
290075Sobrien;;  Copyright 1991, 1993, 1994, 1995, 1996, 1996, 1997, 1998, 1999, 2000,
3169689Skan;;  2001, 2002, 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
490075Sobrien;;  Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl)
590075Sobrien;;  and Martin Simmons (@harleqn.co.uk).
690075Sobrien;;  More major hacks by Richard Earnshaw (rearnsha@arm.com).
790075Sobrien
8132718Skan;; This file is part of GCC.
990075Sobrien
10132718Skan;; GCC is free software; you can redistribute it and/or modify it
11132718Skan;; under the terms of the GNU General Public License as published
12132718Skan;; by the Free Software Foundation; either version 2, or (at your
13132718Skan;; option) any later version.
1490075Sobrien
15132718Skan;; GCC is distributed in the hope that it will be useful, but WITHOUT
16132718Skan;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17132718Skan;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
18132718Skan;; License for more details.
1990075Sobrien
2090075Sobrien;; You should have received a copy of the GNU General Public License
21132718Skan;; along with GCC; see the file COPYING.  If not, write to
22169689Skan;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
23169689Skan;; Boston, MA 02110-1301, USA.
2490075Sobrien
2590075Sobrien;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
2690075Sobrien
2790075Sobrien
2890075Sobrien;;---------------------------------------------------------------------------
2990075Sobrien;; Constants
3090075Sobrien
3190075Sobrien;; Register numbers
3290075Sobrien(define_constants
33169689Skan  [(R0_REGNUM        0)		; First CORE register
34169689Skan   (IP_REGNUM	    12)		; Scratch register
3590075Sobrien   (SP_REGNUM	    13)		; Stack pointer
3690075Sobrien   (LR_REGNUM       14)		; Return address register
3790075Sobrien   (PC_REGNUM	    15)		; Program counter
3890075Sobrien   (CC_REGNUM       24)		; Condition code pseudo register
39169689Skan   (LAST_ARM_REGNUM 15)		;
40169689Skan   (FPA_F0_REGNUM   16)		; FIRST_FPA_REGNUM
41169689Skan   (FPA_F7_REGNUM   23)		; LAST_FPA_REGNUM
4290075Sobrien  ]
4390075Sobrien)
44132718Skan;; 3rd operand to select_dominance_cc_mode
45132718Skan(define_constants
46132718Skan  [(DOM_CC_X_AND_Y  0)
47132718Skan   (DOM_CC_NX_OR_Y  1)
48132718Skan   (DOM_CC_X_OR_Y   2)
49132718Skan  ]
50132718Skan)
5190075Sobrien
5290075Sobrien;; UNSPEC Usage:
5390075Sobrien;; Note: sin and cos are no-longer used.
5490075Sobrien
5590075Sobrien(define_constants
5690075Sobrien  [(UNSPEC_SIN       0)	; `sin' operation (MODE_FLOAT):
5790075Sobrien			;   operand 0 is the result,
5890075Sobrien			;   operand 1 the parameter.
5990075Sobrien   (UNPSEC_COS	     1)	; `cos' operation (MODE_FLOAT):
6090075Sobrien			;   operand 0 is the result,
6190075Sobrien			;   operand 1 the parameter.
6290075Sobrien   (UNSPEC_PUSH_MULT 2)	; `push multiple' operation:
6390075Sobrien			;   operand 0 is the first register,
6490075Sobrien			;   subsequent registers are in parallel (use ...)
6590075Sobrien			;   expressions.
6690075Sobrien   (UNSPEC_PIC_SYM   3) ; A symbol that has been treated properly for pic
6790075Sobrien			;   usage, that is, we will add the pic_register
6890075Sobrien			;   value to it before trying to dereference it.
69117395Skan   (UNSPEC_PIC_BASE  4)	; Adding the PC value to the offset to the
70117395Skan			;   GLOBAL_OFFSET_TABLE.  The operation is fully
71117395Skan			;   described by the RTL but must be wrapped to
72117395Skan			;   prevent combine from trying to rip it apart.
73117395Skan   (UNSPEC_PRLG_STK  5) ; A special barrier that prevents frame accesses 
7490075Sobrien			;   being scheduled before the stack adjustment insn.
7590075Sobrien   (UNSPEC_PROLOGUE_USE 6) ; As USE insns are not meaningful after reload,
7690075Sobrien   			; this unspec is used to prevent the deletion of
7790075Sobrien   			; instructions setting registers for EH handling
7890075Sobrien   			; and stack frame generation.  Operand 0 is the
7990075Sobrien   			; register to "use".
80117395Skan   (UNSPEC_CHECK_ARCH 7); Set CCs to indicate 26-bit or 32-bit mode.
81132718Skan   (UNSPEC_WSHUFH    8) ; Used by the intrinsic form of the iWMMXt WSHUFH instruction.
82132718Skan   (UNSPEC_WACC      9) ; Used by the intrinsic form of the iWMMXt WACC instruction.
83132718Skan   (UNSPEC_TMOVMSK  10) ; Used by the intrinsic form of the iWMMXt TMOVMSK instruction.
84132718Skan   (UNSPEC_WSAD     11) ; Used by the intrinsic form of the iWMMXt WSAD instruction.
85132718Skan   (UNSPEC_WSADZ    12) ; Used by the intrinsic form of the iWMMXt WSADZ instruction.
86132718Skan   (UNSPEC_WMACS    13) ; Used by the intrinsic form of the iWMMXt WMACS instruction.
87132718Skan   (UNSPEC_WMACU    14) ; Used by the intrinsic form of the iWMMXt WMACU instruction.
88132718Skan   (UNSPEC_WMACSZ   15) ; Used by the intrinsic form of the iWMMXt WMACSZ instruction.
89132718Skan   (UNSPEC_WMACUZ   16) ; Used by the intrinsic form of the iWMMXt WMACUZ instruction.
90132718Skan   (UNSPEC_CLRDI    17) ; Used by the intrinsic form of the iWMMXt CLRDI instruction.
91132718Skan   (UNSPEC_WMADDS   18) ; Used by the intrinsic form of the iWMMXt WMADDS instruction.
92132718Skan   (UNSPEC_WMADDU   19) ; Used by the intrinsic form of the iWMMXt WMADDU instruction.
93169689Skan   (UNSPEC_TLS      20) ; A symbol that has been treated properly for TLS usage.
94169689Skan   (UNSPEC_PIC_LABEL 21) ; A label used for PIC access that does not appear in the
95169689Skan                         ; instruction stream.
9690075Sobrien  ]
9790075Sobrien)
9890075Sobrien
9990075Sobrien;; UNSPEC_VOLATILE Usage:
10090075Sobrien
10190075Sobrien(define_constants
10290075Sobrien  [(VUNSPEC_BLOCKAGE 0) ; `blockage' insn to prevent scheduling across an
10390075Sobrien			;   insn in the code.
10490075Sobrien   (VUNSPEC_EPILOGUE 1) ; `epilogue' insn, used to represent any part of the
10590075Sobrien			;   instruction epilogue sequence that isn't expanded
10690075Sobrien			;   into normal RTL.  Used for both normal and sibcall
10790075Sobrien			;   epilogues.
10890075Sobrien   (VUNSPEC_ALIGN    2) ; `align' insn.  Used at the head of a minipool table 
10990075Sobrien			;   for inlined constants.
11090075Sobrien   (VUNSPEC_POOL_END 3) ; `end-of-table'.  Used to mark the end of a minipool
11190075Sobrien			;   table.
11290075Sobrien   (VUNSPEC_POOL_1   4) ; `pool-entry(1)'.  An entry in the constant pool for
11390075Sobrien			;   an 8-bit object.
11490075Sobrien   (VUNSPEC_POOL_2   5) ; `pool-entry(2)'.  An entry in the constant pool for
11590075Sobrien			;   a 16-bit object.
11690075Sobrien   (VUNSPEC_POOL_4   6) ; `pool-entry(4)'.  An entry in the constant pool for
11790075Sobrien			;   a 32-bit object.
11890075Sobrien   (VUNSPEC_POOL_8   7) ; `pool-entry(8)'.  An entry in the constant pool for
11990075Sobrien			;   a 64-bit object.
120132718Skan   (VUNSPEC_TMRC     8) ; Used by the iWMMXt TMRC instruction.
121132718Skan   (VUNSPEC_TMCR     9) ; Used by the iWMMXt TMCR instruction.
122132718Skan   (VUNSPEC_ALIGN8   10) ; 8-byte alignment version of VUNSPEC_ALIGN
123132718Skan   (VUNSPEC_WCMP_EQ  11) ; Used by the iWMMXt WCMPEQ instructions
124132718Skan   (VUNSPEC_WCMP_GTU 12) ; Used by the iWMMXt WCMPGTU instructions
125132718Skan   (VUNSPEC_WCMP_GT  13) ; Used by the iwMMXT WCMPGT instructions
126169689Skan   (VUNSPEC_EH_RETURN 20); Use to override the return address for exception
127169689Skan			 ; handling.
12890075Sobrien  ]
12990075Sobrien)
13090075Sobrien
13190075Sobrien;;---------------------------------------------------------------------------
13290075Sobrien;; Attributes
13390075Sobrien
13490075Sobrien; IS_THUMB is set to 'yes' when we are generating Thumb code, and 'no' when
13590075Sobrien; generating ARM code.  This is used to control the length of some insn
13690075Sobrien; patterns that share the same RTL in both ARM and Thumb code.
13790075Sobrien(define_attr "is_thumb" "no,yes" (const (symbol_ref "thumb_code")))
13890075Sobrien
13990075Sobrien; IS_STRONGARM is set to 'yes' when compiling for StrongARM, it affects
14090075Sobrien; scheduling decisions for the load unit and the multiplier.
141169689Skan(define_attr "is_strongarm" "no,yes" (const (symbol_ref "arm_tune_strongarm")))
14290075Sobrien
143169689Skan; IS_XSCALE is set to 'yes' when compiling for XScale.
144169689Skan(define_attr "is_xscale" "no,yes" (const (symbol_ref "arm_tune_xscale")))
145169689Skan
14690075Sobrien;; Operand number of an input operand that is shifted.  Zero if the
14790075Sobrien;; given instruction does not shift one of its input operands.
14890075Sobrien(define_attr "shift" "" (const_int 0))
14990075Sobrien
15090075Sobrien; Floating Point Unit.  If we only have floating point emulation, then there
15190075Sobrien; is no point in scheduling the floating point insns.  (Well, for best
15290075Sobrien; performance we should try and group them together).
153169689Skan(define_attr "fpu" "none,fpa,fpe2,fpe3,maverick,vfp"
154132718Skan  (const (symbol_ref "arm_fpu_attr")))
15590075Sobrien
15690075Sobrien; LENGTH of an instruction (in bytes)
15790075Sobrien(define_attr "length" "" (const_int 4))
15890075Sobrien
15990075Sobrien; POOL_RANGE is how far away from a constant pool entry that this insn
16090075Sobrien; can be placed.  If the distance is zero, then this insn will never
16190075Sobrien; reference the pool.
16290075Sobrien; NEG_POOL_RANGE is nonzero for insns that can reference a constant pool entry
16390075Sobrien; before its address.
16490075Sobrien(define_attr "pool_range" "" (const_int 0))
16590075Sobrien(define_attr "neg_pool_range" "" (const_int 0))
16690075Sobrien
16790075Sobrien; An assembler sequence may clobber the condition codes without us knowing.
16896263Sobrien; If such an insn references the pool, then we have no way of knowing how,
16996263Sobrien; so use the most conservative value for pool_range.
17090075Sobrien(define_asm_attributes
17196263Sobrien [(set_attr "conds" "clob")
17296263Sobrien  (set_attr "length" "4")
17396263Sobrien  (set_attr "pool_range" "250")])
17490075Sobrien
175169689Skan;; The instruction used to implement a particular pattern.  This
176169689Skan;; information is used by pipeline descriptions to provide accurate
177169689Skan;; scheduling information.
178169689Skan
179169689Skan(define_attr "insn"
180169689Skan        "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"
181169689Skan        (const_string "other"))
182169689Skan
18390075Sobrien; TYPE attribute is used to detect floating point instructions which, if
18490075Sobrien; running on a co-processor can run in parallel with other, basic instructions
18590075Sobrien; If write-buffer scheduling is enabled then it can also be used in the
18690075Sobrien; scheduling of writes.
18790075Sobrien
18890075Sobrien; Classification of each insn
189169689Skan; alu		any alu  instruction that doesn't hit memory or fp
190169689Skan;		regs or have a shifted source operand
191169689Skan; alu_shift	any data instruction that doesn't hit memory or fp
192169689Skan;		regs, but has a source operand shifted by a constant
193169689Skan; alu_shift_reg	any data instruction that doesn't hit memory or fp
194169689Skan;		regs, but has a source operand shifted by a register value
19590075Sobrien; mult		a multiply instruction
19690075Sobrien; block		blockage insn, this blocks all functional units
19790075Sobrien; float		a floating point arithmetic operation (subject to expansion)
19890075Sobrien; fdivd		DFmode floating point division
19990075Sobrien; fdivs		SFmode floating point division
20090075Sobrien; fmul		Floating point multiply
20190075Sobrien; ffmul		Fast floating point multiply
20290075Sobrien; farith	Floating point arithmetic (4 cycle)
20390075Sobrien; ffarith	Fast floating point arithmetic (2 cycle)
20490075Sobrien; float_em	a floating point arithmetic operation that is normally emulated
20590075Sobrien;		even on a machine with an fpa.
20690075Sobrien; f_load	a floating point load from memory
20790075Sobrien; f_store	a floating point store to memory
208169689Skan; f_load[sd]	single/double load from memory
209169689Skan; f_store[sd]	single/double store to memory
210169689Skan; f_flag	a transfer of co-processor flags to the CPSR
21190075Sobrien; f_mem_r	a transfer of a floating point register to a real reg via mem
21290075Sobrien; r_mem_f	the reverse of f_mem_r
21390075Sobrien; f_2_r		fast transfer float to arm (no memory needed)
21490075Sobrien; r_2_f		fast transfer arm to float
215169689Skan; f_cvt		convert floating<->integral
216169689Skan; branch	a branch
21790075Sobrien; call		a subroutine call
218169689Skan; load_byte	load byte(s) from memory to arm registers
219169689Skan; load1		load 1 word from memory to arm registers
220169689Skan; load2         load 2 words from memory to arm registers
221169689Skan; load3         load 3 words from memory to arm registers
222169689Skan; load4         load 4 words from memory to arm registers
223169689Skan; store		store 1 word to memory from arm registers
22490075Sobrien; store2	store 2 words
22590075Sobrien; store3	store 3 words
226169689Skan; store4	store 4 (or more) words
227132718Skan;  Additions for Cirrus Maverick co-processor:
228132718Skan; mav_farith	Floating point arithmetic (4 cycle)
229132718Skan; mav_dmult	Double multiplies (7 cycle)
23090075Sobrien;
23190075Sobrien(define_attr "type"
232169689Skan	"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" 
233169689Skan	(if_then_else 
234169689Skan	 (eq_attr "insn" "smulxy,smlaxy,smlalxy,smulwy,smlawx,mul,muls,mla,mlas,umull,umulls,umlal,umlals,smull,smulls,smlal,smlals")
235169689Skan	 (const_string "mult")
236169689Skan	 (const_string "alu")))
23790075Sobrien
23890075Sobrien; Load scheduling, set from the arm_ld_sched variable
239117395Skan; initialized by arm_override_options() 
24090075Sobrien(define_attr "ldsched" "no,yes" (const (symbol_ref "arm_ld_sched")))
24190075Sobrien
24290075Sobrien; condition codes: this one is used by final_prescan_insn to speed up
24390075Sobrien; conditionalizing instructions.  It saves having to scan the rtl to see if
24490075Sobrien; it uses or alters the condition codes.
24590075Sobrien; 
24690075Sobrien; USE means that the condition codes are used by the insn in the process of
24790075Sobrien;   outputting code, this means (at present) that we can't use the insn in
24890075Sobrien;   inlined branches
24990075Sobrien;
25090075Sobrien; SET means that the purpose of the insn is to set the condition codes in a
25190075Sobrien;   well defined manner.
25290075Sobrien;
25390075Sobrien; CLOB means that the condition codes are altered in an undefined manner, if
25490075Sobrien;   they are altered at all
25590075Sobrien;
25690075Sobrien; JUMP_CLOB is used when the condition cannot be represented by a single
25790075Sobrien;   instruction (UNEQ and LTGT).  These cannot be predicated.
25890075Sobrien;
25990075Sobrien; NOCOND means that the condition codes are neither altered nor affect the
26090075Sobrien;   output of this insn
26190075Sobrien
26290075Sobrien(define_attr "conds" "use,set,clob,jump_clob,nocond"
26390075Sobrien	(if_then_else (eq_attr "type" "call")
264169689Skan	 (const_string "clob")
26590075Sobrien	 (const_string "nocond")))
26690075Sobrien
26790075Sobrien; Predicable means that the insn can be conditionally executed based on
26890075Sobrien; an automatically added predicate (additional patterns are generated by 
26990075Sobrien; gen...).  We default to 'no' because no Thumb patterns match this rule
27090075Sobrien; and not all ARM patterns do.
27190075Sobrien(define_attr "predicable" "no,yes" (const_string "no"))
27290075Sobrien
27390075Sobrien; Only model the write buffer for ARM6 and ARM7.  Earlier processors don't
27490075Sobrien; have one.  Later ones, such as StrongARM, have write-back caches, so don't
275132718Skan; suffer blockages enough to warrant modelling this (and it can adversely
27690075Sobrien; affect the schedule).
277169689Skan(define_attr "model_wbuf" "no,yes" (const (symbol_ref "arm_tune_wbuf")))
27890075Sobrien
27990075Sobrien; WRITE_CONFLICT implies that a read following an unrelated write is likely
28090075Sobrien; to stall the processor.  Used with model_wbuf above.
28190075Sobrien(define_attr "write_conflict" "no,yes"
28290075Sobrien  (if_then_else (eq_attr "type"
283169689Skan		 "block,float_em,f_load,f_store,f_mem_r,r_mem_f,call,load1")
28490075Sobrien		(const_string "yes")
28590075Sobrien		(const_string "no")))
28690075Sobrien
28790075Sobrien; Classify the insns into those that take one cycle and those that take more
28890075Sobrien; than one on the main cpu execution unit.
28990075Sobrien(define_attr "core_cycles" "single,multi"
29090075Sobrien  (if_then_else (eq_attr "type"
291169689Skan		 "alu,alu_shift,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith")
29290075Sobrien		(const_string "single")
29390075Sobrien	        (const_string "multi")))
29490075Sobrien
29590075Sobrien;; FAR_JUMP is "yes" if a BL instruction is used to generate a branch to a
29690075Sobrien;; distant label.  Only applicable to Thumb code.
29790075Sobrien(define_attr "far_jump" "yes,no" (const_string "no"))
29890075Sobrien
29990075Sobrien
300169689Skan;;---------------------------------------------------------------------------
301169689Skan;; Mode macros
30290075Sobrien
303169689Skan; A list of modes that are exactly 64 bits in size.  We use this to expand
304169689Skan; some splits that are the same for all modes when operating on ARM 
305169689Skan; registers.
306169689Skan(define_mode_macro ANY64 [DI DF V8QI V4HI V2SI V2SF])
30790075Sobrien
308169689Skan;;---------------------------------------------------------------------------
309169689Skan;; Predicates
31090075Sobrien
311169689Skan(include "predicates.md")
312169689Skan(include "constraints.md")
31390075Sobrien
314169689Skan;;---------------------------------------------------------------------------
315169689Skan;; Pipeline descriptions
31690075Sobrien
317169689Skan;; Processor type.  This is created automatically from arm-cores.def.
318169689Skan(include "arm-tune.md")
31990075Sobrien
320169689Skan;; True if the generic scheduling description should be used.
32190075Sobrien
322169689Skan(define_attr "generic_sched" "yes,no"
323169689Skan  (const (if_then_else 
324169689Skan          (eq_attr "tune" "arm926ejs,arm1020e,arm1026ejs,arm1136js,arm1136jfs") 
325169689Skan          (const_string "no")
326169689Skan          (const_string "yes"))))
32790075Sobrien
328169689Skan(define_attr "generic_vfp" "yes,no"
329169689Skan  (const (if_then_else
330169689Skan	  (and (eq_attr "fpu" "vfp")
331169689Skan	       (eq_attr "tune" "!arm1020e,arm1022e"))
332169689Skan	  (const_string "yes")
333169689Skan	  (const_string "no"))))
33490075Sobrien
335169689Skan(include "arm-generic.md")
336169689Skan(include "arm926ejs.md")
337169689Skan(include "arm1020e.md")
338169689Skan(include "arm1026ejs.md")
339169689Skan(include "arm1136jfs.md")
34090075Sobrien
34190075Sobrien
34290075Sobrien;;---------------------------------------------------------------------------
34390075Sobrien;; Insn patterns
34490075Sobrien;;
34590075Sobrien;; Addition insns.
34690075Sobrien
34790075Sobrien;; Note: For DImode insns, there is normally no reason why operands should
34890075Sobrien;; not be in the same register, what we don't want is for something being
34990075Sobrien;; written to partially overlap something that is an input.
350132718Skan;; Cirrus 64bit additions should not be split because we have a native
351132718Skan;; 64bit addition instructions.
35290075Sobrien
35390075Sobrien(define_expand "adddi3"
35490075Sobrien [(parallel
35590075Sobrien   [(set (match_operand:DI           0 "s_register_operand" "")
35690075Sobrien	  (plus:DI (match_operand:DI 1 "s_register_operand" "")
35790075Sobrien	           (match_operand:DI 2 "s_register_operand" "")))
35890075Sobrien    (clobber (reg:CC CC_REGNUM))])]
35990075Sobrien  "TARGET_EITHER"
36090075Sobrien  "
361169689Skan  if (TARGET_HARD_FLOAT && TARGET_MAVERICK)
362132718Skan    {
363132718Skan      if (!cirrus_fp_register (operands[0], DImode))
364132718Skan        operands[0] = force_reg (DImode, operands[0]);
365132718Skan      if (!cirrus_fp_register (operands[1], DImode))
366132718Skan        operands[1] = force_reg (DImode, operands[1]);
367132718Skan      emit_insn (gen_cirrus_adddi3 (operands[0], operands[1], operands[2]));
368132718Skan      DONE;
369132718Skan    }
370132718Skan
37190075Sobrien  if (TARGET_THUMB)
37290075Sobrien    {
37390075Sobrien      if (GET_CODE (operands[1]) != REG)
37490075Sobrien        operands[1] = force_reg (SImode, operands[1]);
37590075Sobrien      if (GET_CODE (operands[2]) != REG)
37690075Sobrien        operands[2] = force_reg (SImode, operands[2]);
37790075Sobrien     }
37890075Sobrien  "
37990075Sobrien)
38090075Sobrien
38190075Sobrien(define_insn "*thumb_adddi3"
38290075Sobrien  [(set (match_operand:DI          0 "register_operand" "=l")
38390075Sobrien	(plus:DI (match_operand:DI 1 "register_operand" "%0")
38490075Sobrien		 (match_operand:DI 2 "register_operand" "l")))
38590075Sobrien   (clobber (reg:CC CC_REGNUM))
38690075Sobrien  ]
38790075Sobrien  "TARGET_THUMB"
38890075Sobrien  "add\\t%Q0, %Q0, %Q2\;adc\\t%R0, %R0, %R2"
38990075Sobrien  [(set_attr "length" "4")]
39090075Sobrien)
39190075Sobrien
39290075Sobrien(define_insn_and_split "*arm_adddi3"
39390075Sobrien  [(set (match_operand:DI          0 "s_register_operand" "=&r,&r")
39490075Sobrien	(plus:DI (match_operand:DI 1 "s_register_operand" "%0, 0")
39590075Sobrien		 (match_operand:DI 2 "s_register_operand" "r,  0")))
39690075Sobrien   (clobber (reg:CC CC_REGNUM))]
397169689Skan  "TARGET_ARM && !(TARGET_HARD_FLOAT && TARGET_MAVERICK)"
39890075Sobrien  "#"
39990075Sobrien  "TARGET_ARM && reload_completed"
40090075Sobrien  [(parallel [(set (reg:CC_C CC_REGNUM)
40190075Sobrien		   (compare:CC_C (plus:SI (match_dup 1) (match_dup 2))
40290075Sobrien				 (match_dup 1)))
40390075Sobrien	      (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))])
40490075Sobrien   (set (match_dup 3) (plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))
40590075Sobrien			       (plus:SI (match_dup 4) (match_dup 5))))]
40690075Sobrien  "
40790075Sobrien  {
40890075Sobrien    operands[3] = gen_highpart (SImode, operands[0]);
40990075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
41090075Sobrien    operands[4] = gen_highpart (SImode, operands[1]);
41190075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
41290075Sobrien    operands[5] = gen_highpart (SImode, operands[2]);
41390075Sobrien    operands[2] = gen_lowpart (SImode, operands[2]);
41490075Sobrien  }"
41590075Sobrien  [(set_attr "conds" "clob")
41690075Sobrien   (set_attr "length" "8")]
41790075Sobrien)
41890075Sobrien
41990075Sobrien(define_insn_and_split "*adddi_sesidi_di"
42090075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
42190075Sobrien	(plus:DI (sign_extend:DI
42290075Sobrien		  (match_operand:SI 2 "s_register_operand" "r,r"))
42390075Sobrien		 (match_operand:DI 1 "s_register_operand" "r,0")))
42490075Sobrien   (clobber (reg:CC CC_REGNUM))]
425169689Skan  "TARGET_ARM && !(TARGET_HARD_FLOAT && TARGET_MAVERICK)"
42690075Sobrien  "#"
42790075Sobrien  "TARGET_ARM && reload_completed"
42890075Sobrien  [(parallel [(set (reg:CC_C CC_REGNUM)
42990075Sobrien		   (compare:CC_C (plus:SI (match_dup 1) (match_dup 2))
43090075Sobrien				 (match_dup 1)))
43190075Sobrien	      (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))])
43290075Sobrien   (set (match_dup 3) (plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))
43390075Sobrien			       (plus:SI (ashiftrt:SI (match_dup 2)
43490075Sobrien						     (const_int 31))
43590075Sobrien					(match_dup 4))))]
43690075Sobrien  "
43790075Sobrien  {
43890075Sobrien    operands[3] = gen_highpart (SImode, operands[0]);
43990075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
44090075Sobrien    operands[4] = gen_highpart (SImode, operands[1]);
44190075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
44290075Sobrien    operands[2] = gen_lowpart (SImode, operands[2]);
44390075Sobrien  }"
44490075Sobrien  [(set_attr "conds" "clob")
44590075Sobrien   (set_attr "length" "8")]
44690075Sobrien)
44790075Sobrien
44890075Sobrien(define_insn_and_split "*adddi_zesidi_di"
44990075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
45090075Sobrien	(plus:DI (zero_extend:DI
45190075Sobrien		  (match_operand:SI 2 "s_register_operand" "r,r"))
45290075Sobrien		 (match_operand:DI 1 "s_register_operand" "r,0")))
45390075Sobrien   (clobber (reg:CC CC_REGNUM))]
454169689Skan  "TARGET_ARM && !(TARGET_HARD_FLOAT && TARGET_MAVERICK)"
45590075Sobrien  "#"
45690075Sobrien  "TARGET_ARM && reload_completed"
45790075Sobrien  [(parallel [(set (reg:CC_C CC_REGNUM)
45890075Sobrien		   (compare:CC_C (plus:SI (match_dup 1) (match_dup 2))
45990075Sobrien				 (match_dup 1)))
46090075Sobrien	      (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))])
46190075Sobrien   (set (match_dup 3) (plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))
46290075Sobrien			       (plus:SI (match_dup 4) (const_int 0))))]
46390075Sobrien  "
46490075Sobrien  {
46590075Sobrien    operands[3] = gen_highpart (SImode, operands[0]);
46690075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
46790075Sobrien    operands[4] = gen_highpart (SImode, operands[1]);
46890075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
46990075Sobrien    operands[2] = gen_lowpart (SImode, operands[2]);
47090075Sobrien  }"
47190075Sobrien  [(set_attr "conds" "clob")
47290075Sobrien   (set_attr "length" "8")]
47390075Sobrien)
47490075Sobrien
47590075Sobrien(define_expand "addsi3"
47690075Sobrien  [(set (match_operand:SI          0 "s_register_operand" "")
47790075Sobrien	(plus:SI (match_operand:SI 1 "s_register_operand" "")
47890075Sobrien		 (match_operand:SI 2 "reg_or_int_operand" "")))]
47990075Sobrien  "TARGET_EITHER"
48090075Sobrien  "
48190075Sobrien  if (TARGET_ARM && GET_CODE (operands[2]) == CONST_INT)
48290075Sobrien    {
483169689Skan      arm_split_constant (PLUS, SImode, NULL_RTX,
484169689Skan	                  INTVAL (operands[2]), operands[0], operands[1],
485169689Skan			  optimize && !no_new_pseudos);
48690075Sobrien      DONE;
48790075Sobrien    }
48890075Sobrien  "
48990075Sobrien)
49090075Sobrien
491132718Skan; If there is a scratch available, this will be faster than synthesizing the
49290075Sobrien; addition.
49390075Sobrien(define_peephole2
49490075Sobrien  [(match_scratch:SI 3 "r")
495169689Skan   (set (match_operand:SI          0 "arm_general_register_operand" "")
496169689Skan	(plus:SI (match_operand:SI 1 "arm_general_register_operand" "")
49790075Sobrien		 (match_operand:SI 2 "const_int_operand"  "")))]
49890075Sobrien  "TARGET_ARM &&
49990075Sobrien   !(const_ok_for_arm (INTVAL (operands[2]))
50090075Sobrien     || const_ok_for_arm (-INTVAL (operands[2])))
50190075Sobrien    && const_ok_for_arm (~INTVAL (operands[2]))"
50290075Sobrien  [(set (match_dup 3) (match_dup 2))
50390075Sobrien   (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 3)))]
50490075Sobrien  ""
50590075Sobrien)
50690075Sobrien
50790075Sobrien(define_insn_and_split "*arm_addsi3"
50890075Sobrien  [(set (match_operand:SI          0 "s_register_operand" "=r,r,r")
50990075Sobrien	(plus:SI (match_operand:SI 1 "s_register_operand" "%r,r,r")
51090075Sobrien		 (match_operand:SI 2 "reg_or_int_operand" "rI,L,?n")))]
51190075Sobrien  "TARGET_ARM"
51290075Sobrien  "@
51390075Sobrien   add%?\\t%0, %1, %2
51490075Sobrien   sub%?\\t%0, %1, #%n2
51590075Sobrien   #"
51690075Sobrien  "TARGET_ARM &&
51790075Sobrien   GET_CODE (operands[2]) == CONST_INT
51890075Sobrien   && !(const_ok_for_arm (INTVAL (operands[2]))
51990075Sobrien        || const_ok_for_arm (-INTVAL (operands[2])))"
52090075Sobrien  [(clobber (const_int 0))]
52190075Sobrien  "
522169689Skan  arm_split_constant (PLUS, SImode, curr_insn,
523169689Skan	              INTVAL (operands[2]), operands[0],
52490075Sobrien		      operands[1], 0);
52590075Sobrien  DONE;
52690075Sobrien  "
52790075Sobrien  [(set_attr "length" "4,4,16")
52890075Sobrien   (set_attr "predicable" "yes")]
52990075Sobrien)
53090075Sobrien
53190075Sobrien;; Register group 'k' is a single register group containing only the stack
53290075Sobrien;; register.  Trying to reload it will always fail catastrophically,
53390075Sobrien;; so never allow those alternatives to match if reloading is needed.
53490075Sobrien
53590075Sobrien(define_insn "*thumb_addsi3"
53690075Sobrien  [(set (match_operand:SI          0 "register_operand" "=l,l,l,*r,*h,l,!k")
53790075Sobrien	(plus:SI (match_operand:SI 1 "register_operand" "%0,0,l,*0,*0,!k,!k")
53890075Sobrien		 (match_operand:SI 2 "nonmemory_operand" "I,J,lL,*h,*r,!M,!O")))]
53990075Sobrien  "TARGET_THUMB"
54090075Sobrien  "*
54190075Sobrien   static const char * const asms[] = 
54290075Sobrien   {
54390075Sobrien     \"add\\t%0, %0, %2\",
54490075Sobrien     \"sub\\t%0, %0, #%n2\",
54590075Sobrien     \"add\\t%0, %1, %2\",
54690075Sobrien     \"add\\t%0, %0, %2\",
54790075Sobrien     \"add\\t%0, %0, %2\",
54890075Sobrien     \"add\\t%0, %1, %2\",
54990075Sobrien     \"add\\t%0, %1, %2\"
55090075Sobrien   };
55190075Sobrien   if ((which_alternative == 2 || which_alternative == 6)
55290075Sobrien       && GET_CODE (operands[2]) == CONST_INT
55390075Sobrien       && INTVAL (operands[2]) < 0)
55490075Sobrien     return \"sub\\t%0, %1, #%n2\";
55590075Sobrien   return asms[which_alternative];
55690075Sobrien  "
55790075Sobrien  [(set_attr "length" "2")]
55890075Sobrien)
55990075Sobrien
56090075Sobrien;; Reloading and elimination of the frame pointer can
56190075Sobrien;; sometimes cause this optimization to be missed.
56290075Sobrien(define_peephole2
563169689Skan  [(set (match_operand:SI 0 "arm_general_register_operand" "")
564117395Skan	(match_operand:SI 1 "const_int_operand" ""))
56590075Sobrien   (set (match_dup 0)
566169689Skan	(plus:SI (match_dup 0) (reg:SI SP_REGNUM)))]
56790075Sobrien  "TARGET_THUMB
56890075Sobrien   && (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) < 1024
56990075Sobrien   && (INTVAL (operands[1]) & 3) == 0"
570169689Skan  [(set (match_dup 0) (plus:SI (reg:SI SP_REGNUM) (match_dup 1)))]
57190075Sobrien  ""
57290075Sobrien)
57390075Sobrien
57490075Sobrien(define_insn "*addsi3_compare0"
57590075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
57690075Sobrien	(compare:CC_NOOV
57790075Sobrien	 (plus:SI (match_operand:SI 1 "s_register_operand" "r, r")
57890075Sobrien		  (match_operand:SI 2 "arm_add_operand"    "rI,L"))
57990075Sobrien	 (const_int 0)))
58090075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r,r")
58190075Sobrien	(plus:SI (match_dup 1) (match_dup 2)))]
58290075Sobrien  "TARGET_ARM"
58390075Sobrien  "@
58490075Sobrien   add%?s\\t%0, %1, %2
58590075Sobrien   sub%?s\\t%0, %1, #%n2"
58690075Sobrien  [(set_attr "conds" "set")]
58790075Sobrien)
58890075Sobrien
58990075Sobrien(define_insn "*addsi3_compare0_scratch"
59090075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
59190075Sobrien	(compare:CC_NOOV
59290075Sobrien	 (plus:SI (match_operand:SI 0 "s_register_operand" "r, r")
59390075Sobrien		  (match_operand:SI 1 "arm_add_operand"    "rI,L"))
59490075Sobrien	 (const_int 0)))]
59590075Sobrien  "TARGET_ARM"
59690075Sobrien  "@
59790075Sobrien   cmn%?\\t%0, %1
59890075Sobrien   cmp%?\\t%0, #%n1"
59990075Sobrien  [(set_attr "conds" "set")]
60090075Sobrien)
60190075Sobrien
602169689Skan(define_insn "*compare_negsi_si"
603169689Skan  [(set (reg:CC_Z CC_REGNUM)
604169689Skan	(compare:CC_Z
605169689Skan	 (neg:SI (match_operand:SI 0 "s_register_operand" "r"))
606169689Skan	 (match_operand:SI 1 "s_register_operand" "r")))]
60790075Sobrien  "TARGET_ARM"
608169689Skan  "cmn%?\\t%1, %0"
60990075Sobrien  [(set_attr "conds" "set")]
61090075Sobrien)
61190075Sobrien
612132718Skan;; This is the canonicalization of addsi3_compare0_for_combiner when the
613132718Skan;; addend is a constant.
614132718Skan(define_insn "*cmpsi2_addneg"
615132718Skan  [(set (reg:CC CC_REGNUM)
616132718Skan	(compare:CC
617132718Skan	 (match_operand:SI 1 "s_register_operand" "r,r")
618132718Skan	 (match_operand:SI 2 "arm_addimm_operand" "I,L")))
619132718Skan   (set (match_operand:SI 0 "s_register_operand" "=r,r")
620132718Skan	(plus:SI (match_dup 1)
621132718Skan		 (match_operand:SI 3 "arm_addimm_operand" "L,I")))]
622132718Skan  "TARGET_ARM && INTVAL (operands[2]) == -INTVAL (operands[3])"
623132718Skan  "@
624132718Skan   sub%?s\\t%0, %1, %2
625132718Skan   add%?s\\t%0, %1, #%n2"
626132718Skan  [(set_attr "conds" "set")]
627132718Skan)
628132718Skan
629132718Skan;; Convert the sequence
630132718Skan;;  sub  rd, rn, #1
631132718Skan;;  cmn  rd, #1	(equivalent to cmp rd, #-1)
632132718Skan;;  bne  dest
633132718Skan;; into
634132718Skan;;  subs rd, rn, #1
635132718Skan;;  bcs  dest	((unsigned)rn >= 1)
636132718Skan;; similarly for the beq variant using bcc.
637132718Skan;; This is a common looping idiom (while (n--))
638132718Skan(define_peephole2
639169689Skan  [(set (match_operand:SI 0 "arm_general_register_operand" "")
640169689Skan	(plus:SI (match_operand:SI 1 "arm_general_register_operand" "")
641132718Skan		 (const_int -1)))
642132718Skan   (set (match_operand 2 "cc_register" "")
643132718Skan	(compare (match_dup 0) (const_int -1)))
644132718Skan   (set (pc)
645132718Skan	(if_then_else (match_operator 3 "equality_operator"
646132718Skan		       [(match_dup 2) (const_int 0)])
647132718Skan		      (match_operand 4 "" "")
648132718Skan		      (match_operand 5 "" "")))]
649132718Skan  "TARGET_ARM && peep2_reg_dead_p (3, operands[2])"
650132718Skan  [(parallel[
651132718Skan    (set (match_dup 2)
652132718Skan	 (compare:CC
653132718Skan	  (match_dup 1) (const_int 1)))
654132718Skan    (set (match_dup 0) (plus:SI (match_dup 1) (const_int -1)))])
655132718Skan   (set (pc)
656132718Skan	(if_then_else (match_op_dup 3 [(match_dup 2) (const_int 0)])
657132718Skan		      (match_dup 4)
658132718Skan		      (match_dup 5)))]
659132718Skan  "operands[2] = gen_rtx_REG (CCmode, CC_REGNUM);
660132718Skan   operands[3] = gen_rtx_fmt_ee ((GET_CODE (operands[3]) == NE
661132718Skan				  ? GEU : LTU),
662132718Skan				 VOIDmode, 
663132718Skan				 operands[2], const0_rtx);"
664132718Skan)
665132718Skan
66690075Sobrien;; The next four insns work because they compare the result with one of
66790075Sobrien;; the operands, and we know that the use of the condition code is
66890075Sobrien;; either GEU or LTU, so we can use the carry flag from the addition
66990075Sobrien;; instead of doing the compare a second time.
67090075Sobrien(define_insn "*addsi3_compare_op1"
67190075Sobrien  [(set (reg:CC_C CC_REGNUM)
67290075Sobrien	(compare:CC_C
67390075Sobrien	 (plus:SI (match_operand:SI 1 "s_register_operand" "r,r")
67490075Sobrien		  (match_operand:SI 2 "arm_add_operand" "rI,L"))
67590075Sobrien	 (match_dup 1)))
67690075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r,r")
67790075Sobrien	(plus:SI (match_dup 1) (match_dup 2)))]
67890075Sobrien  "TARGET_ARM"
67990075Sobrien  "@
68090075Sobrien   add%?s\\t%0, %1, %2
68190075Sobrien   sub%?s\\t%0, %1, #%n2"
68290075Sobrien  [(set_attr "conds" "set")]
68390075Sobrien)
68490075Sobrien
68590075Sobrien(define_insn "*addsi3_compare_op2"
68690075Sobrien  [(set (reg:CC_C CC_REGNUM)
68790075Sobrien	(compare:CC_C
68890075Sobrien	 (plus:SI (match_operand:SI 1 "s_register_operand" "r,r")
68990075Sobrien		  (match_operand:SI 2 "arm_add_operand" "rI,L"))
69090075Sobrien	 (match_dup 2)))
69190075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r,r")
69290075Sobrien	(plus:SI (match_dup 1) (match_dup 2)))]
69390075Sobrien  "TARGET_ARM"
69490075Sobrien  "@
69590075Sobrien   add%?s\\t%0, %1, %2
69690075Sobrien   sub%?s\\t%0, %1, #%n2"
69790075Sobrien  [(set_attr "conds" "set")]
69890075Sobrien)
69990075Sobrien
70090075Sobrien(define_insn "*compare_addsi2_op0"
70190075Sobrien  [(set (reg:CC_C CC_REGNUM)
70290075Sobrien	(compare:CC_C
70390075Sobrien	 (plus:SI (match_operand:SI 0 "s_register_operand" "r,r")
70490075Sobrien		  (match_operand:SI 1 "arm_add_operand" "rI,L"))
70590075Sobrien	 (match_dup 0)))]
70690075Sobrien  "TARGET_ARM"
70790075Sobrien  "@
70890075Sobrien   cmn%?\\t%0, %1
70990075Sobrien   cmp%?\\t%0, #%n1"
71090075Sobrien  [(set_attr "conds" "set")]
71190075Sobrien)
71290075Sobrien
71390075Sobrien(define_insn "*compare_addsi2_op1"
71490075Sobrien  [(set (reg:CC_C CC_REGNUM)
71590075Sobrien	(compare:CC_C
71690075Sobrien	 (plus:SI (match_operand:SI 0 "s_register_operand" "r,r")
71790075Sobrien		  (match_operand:SI 1 "arm_add_operand" "rI,L"))
71890075Sobrien	 (match_dup 1)))]
71990075Sobrien  "TARGET_ARM"
72090075Sobrien  "@
72190075Sobrien   cmn%?\\t%0, %1
72290075Sobrien   cmp%?\\t%0, #%n1"
72390075Sobrien  [(set_attr "conds" "set")]
72490075Sobrien)
72590075Sobrien
72690075Sobrien(define_insn "*addsi3_carryin"
72790075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
72890075Sobrien	(plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))
72990075Sobrien		 (plus:SI (match_operand:SI 1 "s_register_operand" "r")
73090075Sobrien			  (match_operand:SI 2 "arm_rhs_operand" "rI"))))]
73190075Sobrien  "TARGET_ARM"
73290075Sobrien  "adc%?\\t%0, %1, %2"
73390075Sobrien  [(set_attr "conds" "use")]
73490075Sobrien)
73590075Sobrien
73690075Sobrien(define_insn "*addsi3_carryin_shift"
737132718Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
73890075Sobrien	(plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))
73990075Sobrien		 (plus:SI
74090075Sobrien		   (match_operator:SI 2 "shift_operator"
741132718Skan		      [(match_operand:SI 3 "s_register_operand" "r")
742132718Skan		       (match_operand:SI 4 "reg_or_int_operand" "rM")])
743132718Skan		    (match_operand:SI 1 "s_register_operand" "r"))))]
74490075Sobrien  "TARGET_ARM"
74590075Sobrien  "adc%?\\t%0, %1, %3%S2"
746169689Skan  [(set_attr "conds" "use")
747169689Skan   (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "")
748169689Skan		      (const_string "alu_shift")
749169689Skan		      (const_string "alu_shift_reg")))]
75090075Sobrien)
75190075Sobrien
75290075Sobrien(define_insn "*addsi3_carryin_alt1"
75390075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
75490075Sobrien	(plus:SI (plus:SI (match_operand:SI 1 "s_register_operand" "r")
75590075Sobrien			  (match_operand:SI 2 "arm_rhs_operand" "rI"))
75690075Sobrien		 (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))]
75790075Sobrien  "TARGET_ARM"
75890075Sobrien  "adc%?\\t%0, %1, %2"
75990075Sobrien  [(set_attr "conds" "use")]
76090075Sobrien)
76190075Sobrien
76290075Sobrien(define_insn "*addsi3_carryin_alt2"
76390075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
76490075Sobrien	(plus:SI (plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))
76590075Sobrien			  (match_operand:SI 1 "s_register_operand" "r"))
76690075Sobrien		 (match_operand:SI 2 "arm_rhs_operand" "rI")))]
76790075Sobrien  "TARGET_ARM"
76890075Sobrien  "adc%?\\t%0, %1, %2"
76990075Sobrien  [(set_attr "conds" "use")]
77090075Sobrien)
77190075Sobrien
77290075Sobrien(define_insn "*addsi3_carryin_alt3"
77390075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
77490075Sobrien	(plus:SI (plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))
77590075Sobrien			  (match_operand:SI 2 "arm_rhs_operand" "rI"))
77690075Sobrien		 (match_operand:SI 1 "s_register_operand" "r")))]
77790075Sobrien  "TARGET_ARM"
77890075Sobrien  "adc%?\\t%0, %1, %2"
77990075Sobrien  [(set_attr "conds" "use")]
78090075Sobrien)
78190075Sobrien
78290075Sobrien(define_insn "incscc"
78390075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
78490075Sobrien        (plus:SI (match_operator:SI 2 "arm_comparison_operator"
78590075Sobrien                    [(match_operand:CC 3 "cc_register" "") (const_int 0)])
78690075Sobrien                 (match_operand:SI 1 "s_register_operand" "0,?r")))]
78790075Sobrien  "TARGET_ARM"
78890075Sobrien  "@
78990075Sobrien  add%d2\\t%0, %1, #1
79090075Sobrien  mov%D2\\t%0, %1\;add%d2\\t%0, %1, #1"
79190075Sobrien  [(set_attr "conds" "use")
79290075Sobrien   (set_attr "length" "4,8")]
79390075Sobrien)
79490075Sobrien
795132718Skan; transform ((x << y) - 1) to ~(~(x-1) << y)  Where X is a constant.
796132718Skan(define_split
797132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
798132718Skan	(plus:SI (ashift:SI (match_operand:SI 1 "const_int_operand" "")
799132718Skan			    (match_operand:SI 2 "s_register_operand" ""))
800132718Skan		 (const_int -1)))
801132718Skan   (clobber (match_operand:SI 3 "s_register_operand" ""))]
802132718Skan  "TARGET_ARM"
803132718Skan  [(set (match_dup 3) (match_dup 1))
804132718Skan   (set (match_dup 0) (not:SI (ashift:SI (match_dup 3) (match_dup 2))))]
805132718Skan  "
806132718Skan  operands[1] = GEN_INT (~(INTVAL (operands[1]) - 1));
807132718Skan")
80890075Sobrien
809132718Skan(define_expand "addsf3"
810132718Skan  [(set (match_operand:SF          0 "s_register_operand" "")
811132718Skan	(plus:SF (match_operand:SF 1 "s_register_operand" "")
812169689Skan		 (match_operand:SF 2 "arm_float_add_operand" "")))]
813169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT"
814132718Skan  "
815169689Skan  if (TARGET_MAVERICK
816132718Skan      && !cirrus_fp_register (operands[2], SFmode))
817132718Skan    operands[2] = force_reg (SFmode, operands[2]);
818132718Skan")
81990075Sobrien
820132718Skan(define_expand "adddf3"
821132718Skan  [(set (match_operand:DF          0 "s_register_operand" "")
822132718Skan	(plus:DF (match_operand:DF 1 "s_register_operand" "")
823169689Skan		 (match_operand:DF 2 "arm_float_add_operand" "")))]
824169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT"
825132718Skan  "
826169689Skan  if (TARGET_MAVERICK
827132718Skan      && !cirrus_fp_register (operands[2], DFmode))
828132718Skan    operands[2] = force_reg (DFmode, operands[2]);
829132718Skan")
83090075Sobrien
83190075Sobrien(define_expand "subdi3"
83290075Sobrien [(parallel
83390075Sobrien   [(set (match_operand:DI            0 "s_register_operand" "")
83490075Sobrien	  (minus:DI (match_operand:DI 1 "s_register_operand" "")
83590075Sobrien	            (match_operand:DI 2 "s_register_operand" "")))
83690075Sobrien    (clobber (reg:CC CC_REGNUM))])]
83790075Sobrien  "TARGET_EITHER"
83890075Sobrien  "
839169689Skan  if (TARGET_HARD_FLOAT && TARGET_MAVERICK
840132718Skan      && TARGET_ARM
841132718Skan      && cirrus_fp_register (operands[0], DImode)
842132718Skan      && cirrus_fp_register (operands[1], DImode))
843132718Skan    {
844132718Skan      emit_insn (gen_cirrus_subdi3 (operands[0], operands[1], operands[2]));
845132718Skan      DONE;
846132718Skan    }
847132718Skan
84890075Sobrien  if (TARGET_THUMB)
84990075Sobrien    {
85090075Sobrien      if (GET_CODE (operands[1]) != REG)
85190075Sobrien        operands[1] = force_reg (SImode, operands[1]);
85290075Sobrien      if (GET_CODE (operands[2]) != REG)
85390075Sobrien        operands[2] = force_reg (SImode, operands[2]);
85490075Sobrien     }	
85590075Sobrien  "
85690075Sobrien)
85790075Sobrien
85890075Sobrien(define_insn "*arm_subdi3"
85990075Sobrien  [(set (match_operand:DI           0 "s_register_operand" "=&r,&r,&r")
86090075Sobrien	(minus:DI (match_operand:DI 1 "s_register_operand" "0,r,0")
86190075Sobrien		  (match_operand:DI 2 "s_register_operand" "r,0,0")))
86290075Sobrien   (clobber (reg:CC CC_REGNUM))]
86390075Sobrien  "TARGET_ARM"
86490075Sobrien  "subs\\t%Q0, %Q1, %Q2\;sbc\\t%R0, %R1, %R2"
86590075Sobrien  [(set_attr "conds" "clob")
86690075Sobrien   (set_attr "length" "8")]
86790075Sobrien)
86890075Sobrien
86990075Sobrien(define_insn "*thumb_subdi3"
87090075Sobrien  [(set (match_operand:DI           0 "register_operand" "=l")
87190075Sobrien	(minus:DI (match_operand:DI 1 "register_operand"  "0")
87290075Sobrien		  (match_operand:DI 2 "register_operand"  "l")))
87390075Sobrien   (clobber (reg:CC CC_REGNUM))]
87490075Sobrien  "TARGET_THUMB"
87590075Sobrien  "sub\\t%Q0, %Q0, %Q2\;sbc\\t%R0, %R0, %R2"
87690075Sobrien  [(set_attr "length" "4")]
87790075Sobrien)
87890075Sobrien
87990075Sobrien(define_insn "*subdi_di_zesidi"
88090075Sobrien  [(set (match_operand:DI           0 "s_register_operand" "=&r,&r")
88190075Sobrien	(minus:DI (match_operand:DI 1 "s_register_operand"  "?r,0")
88290075Sobrien		  (zero_extend:DI
88390075Sobrien		   (match_operand:SI 2 "s_register_operand"  "r,r"))))
88490075Sobrien   (clobber (reg:CC CC_REGNUM))]
88590075Sobrien  "TARGET_ARM"
88690075Sobrien  "subs\\t%Q0, %Q1, %2\;sbc\\t%R0, %R1, #0"
88790075Sobrien  [(set_attr "conds" "clob")
88890075Sobrien   (set_attr "length" "8")]
88990075Sobrien)
89090075Sobrien
89190075Sobrien(define_insn "*subdi_di_sesidi"
89290075Sobrien  [(set (match_operand:DI            0 "s_register_operand" "=&r,&r")
89390075Sobrien	(minus:DI (match_operand:DI  1 "s_register_operand"  "r,0")
89490075Sobrien		  (sign_extend:DI
89590075Sobrien		   (match_operand:SI 2 "s_register_operand"  "r,r"))))
89690075Sobrien   (clobber (reg:CC CC_REGNUM))]
89790075Sobrien  "TARGET_ARM"
89890075Sobrien  "subs\\t%Q0, %Q1, %2\;sbc\\t%R0, %R1, %2, asr #31"
89990075Sobrien  [(set_attr "conds" "clob")
90090075Sobrien   (set_attr "length" "8")]
90190075Sobrien)
90290075Sobrien
90390075Sobrien(define_insn "*subdi_zesidi_di"
90490075Sobrien  [(set (match_operand:DI            0 "s_register_operand" "=&r,&r")
90590075Sobrien	(minus:DI (zero_extend:DI
90690075Sobrien		   (match_operand:SI 2 "s_register_operand"  "r,r"))
90790075Sobrien		  (match_operand:DI  1 "s_register_operand" "?r,0")))
90890075Sobrien   (clobber (reg:CC CC_REGNUM))]
90990075Sobrien  "TARGET_ARM"
91090075Sobrien  "rsbs\\t%Q0, %Q1, %2\;rsc\\t%R0, %R1, #0"
91190075Sobrien  [(set_attr "conds" "clob")
91290075Sobrien   (set_attr "length" "8")]
91390075Sobrien)
91490075Sobrien
91590075Sobrien(define_insn "*subdi_sesidi_di"
91690075Sobrien  [(set (match_operand:DI            0 "s_register_operand" "=&r,&r")
91790075Sobrien	(minus:DI (sign_extend:DI
91890075Sobrien		   (match_operand:SI 2 "s_register_operand"   "r,r"))
91990075Sobrien		  (match_operand:DI  1 "s_register_operand"  "?r,0")))
92090075Sobrien   (clobber (reg:CC CC_REGNUM))]
92190075Sobrien  "TARGET_ARM"
92290075Sobrien  "rsbs\\t%Q0, %Q1, %2\;rsc\\t%R0, %R1, %2, asr #31"
92390075Sobrien  [(set_attr "conds" "clob")
92490075Sobrien   (set_attr "length" "8")]
92590075Sobrien)
92690075Sobrien
92790075Sobrien(define_insn "*subdi_zesidi_zesidi"
92890075Sobrien  [(set (match_operand:DI            0 "s_register_operand" "=r")
92990075Sobrien	(minus:DI (zero_extend:DI
93090075Sobrien		   (match_operand:SI 1 "s_register_operand"  "r"))
93190075Sobrien		  (zero_extend:DI
93290075Sobrien		   (match_operand:SI 2 "s_register_operand"  "r"))))
93390075Sobrien   (clobber (reg:CC CC_REGNUM))]
93490075Sobrien  "TARGET_ARM"
93590075Sobrien  "subs\\t%Q0, %1, %2\;rsc\\t%R0, %1, %1"
93690075Sobrien  [(set_attr "conds" "clob")
93790075Sobrien   (set_attr "length" "8")]
93890075Sobrien)
93990075Sobrien
94090075Sobrien(define_expand "subsi3"
94190075Sobrien  [(set (match_operand:SI           0 "s_register_operand" "")
94290075Sobrien	(minus:SI (match_operand:SI 1 "reg_or_int_operand" "")
94390075Sobrien		  (match_operand:SI 2 "s_register_operand" "")))]
94490075Sobrien  "TARGET_EITHER"
94590075Sobrien  "
94690075Sobrien  if (GET_CODE (operands[1]) == CONST_INT)
94790075Sobrien    {
94890075Sobrien      if (TARGET_ARM)
94990075Sobrien        {
950169689Skan          arm_split_constant (MINUS, SImode, NULL_RTX,
951169689Skan	                      INTVAL (operands[1]), operands[0],
952169689Skan	  		      operands[2], optimize && !no_new_pseudos);
95390075Sobrien          DONE;
95490075Sobrien	}
95590075Sobrien      else /* TARGET_THUMB */
95690075Sobrien        operands[1] = force_reg (SImode, operands[1]);
95790075Sobrien    }
95890075Sobrien  "
95990075Sobrien)
96090075Sobrien
96190075Sobrien(define_insn "*thumb_subsi3_insn"
96290075Sobrien  [(set (match_operand:SI           0 "register_operand" "=l")
96390075Sobrien	(minus:SI (match_operand:SI 1 "register_operand" "l")
96490075Sobrien		  (match_operand:SI 2 "register_operand" "l")))]
96590075Sobrien  "TARGET_THUMB"
96690075Sobrien  "sub\\t%0, %1, %2"
96790075Sobrien  [(set_attr "length" "2")]
96890075Sobrien)
96990075Sobrien
97090075Sobrien(define_insn_and_split "*arm_subsi3_insn"
97190075Sobrien  [(set (match_operand:SI           0 "s_register_operand" "=r,r")
97290075Sobrien	(minus:SI (match_operand:SI 1 "reg_or_int_operand" "rI,?n")
97390075Sobrien		  (match_operand:SI 2 "s_register_operand" "r,r")))]
97490075Sobrien  "TARGET_ARM"
97590075Sobrien  "@
97690075Sobrien   rsb%?\\t%0, %2, %1
97790075Sobrien   #"
97890075Sobrien  "TARGET_ARM
97990075Sobrien   && GET_CODE (operands[1]) == CONST_INT
98090075Sobrien   && !const_ok_for_arm (INTVAL (operands[1]))"
98190075Sobrien  [(clobber (const_int 0))]
98290075Sobrien  "
983169689Skan  arm_split_constant (MINUS, SImode, curr_insn,
984169689Skan                      INTVAL (operands[1]), operands[0], operands[2], 0);
98590075Sobrien  DONE;
98690075Sobrien  "
98790075Sobrien  [(set_attr "length" "4,16")
98890075Sobrien   (set_attr "predicable" "yes")]
98990075Sobrien)
99090075Sobrien
99190075Sobrien(define_peephole2
99290075Sobrien  [(match_scratch:SI 3 "r")
993169689Skan   (set (match_operand:SI 0 "arm_general_register_operand" "")
99490075Sobrien	(minus:SI (match_operand:SI 1 "const_int_operand" "")
995169689Skan		  (match_operand:SI 2 "arm_general_register_operand" "")))]
99690075Sobrien  "TARGET_ARM
99790075Sobrien   && !const_ok_for_arm (INTVAL (operands[1]))
99890075Sobrien   && const_ok_for_arm (~INTVAL (operands[1]))"
99990075Sobrien  [(set (match_dup 3) (match_dup 1))
100090075Sobrien   (set (match_dup 0) (minus:SI (match_dup 3) (match_dup 2)))]
100190075Sobrien  ""
100290075Sobrien)
100390075Sobrien
100490075Sobrien(define_insn "*subsi3_compare0"
100590075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
100690075Sobrien	(compare:CC_NOOV
100790075Sobrien	 (minus:SI (match_operand:SI 1 "arm_rhs_operand" "r,I")
100890075Sobrien		   (match_operand:SI 2 "arm_rhs_operand" "rI,r"))
100990075Sobrien	 (const_int 0)))
101090075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r,r")
101190075Sobrien	(minus:SI (match_dup 1) (match_dup 2)))]
101290075Sobrien  "TARGET_ARM"
101390075Sobrien  "@
101490075Sobrien   sub%?s\\t%0, %1, %2
101590075Sobrien   rsb%?s\\t%0, %2, %1"
101690075Sobrien  [(set_attr "conds" "set")]
101790075Sobrien)
101890075Sobrien
101990075Sobrien(define_insn "decscc"
102090075Sobrien  [(set (match_operand:SI            0 "s_register_operand" "=r,r")
102190075Sobrien        (minus:SI (match_operand:SI  1 "s_register_operand" "0,?r")
102290075Sobrien		  (match_operator:SI 2 "arm_comparison_operator"
102390075Sobrien                   [(match_operand   3 "cc_register" "") (const_int 0)])))]
102490075Sobrien  "TARGET_ARM"
102590075Sobrien  "@
102690075Sobrien   sub%d2\\t%0, %1, #1
102790075Sobrien   mov%D2\\t%0, %1\;sub%d2\\t%0, %1, #1"
102890075Sobrien  [(set_attr "conds" "use")
102990075Sobrien   (set_attr "length" "*,8")]
103090075Sobrien)
103190075Sobrien
1032132718Skan(define_expand "subsf3"
1033132718Skan  [(set (match_operand:SF           0 "s_register_operand" "")
1034169689Skan	(minus:SF (match_operand:SF 1 "arm_float_rhs_operand" "")
1035169689Skan		  (match_operand:SF 2 "arm_float_rhs_operand" "")))]
1036169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT"
1037132718Skan  "
1038169689Skan  if (TARGET_MAVERICK)
1039132718Skan    {
1040132718Skan      if (!cirrus_fp_register (operands[1], SFmode))
1041132718Skan        operands[1] = force_reg (SFmode, operands[1]);
1042132718Skan      if (!cirrus_fp_register (operands[2], SFmode))
1043132718Skan        operands[2] = force_reg (SFmode, operands[2]);
1044132718Skan    }
1045132718Skan")
104690075Sobrien
1047132718Skan(define_expand "subdf3"
1048132718Skan  [(set (match_operand:DF           0 "s_register_operand" "")
1049169689Skan	(minus:DF (match_operand:DF 1 "arm_float_rhs_operand" "")
1050169689Skan		  (match_operand:DF 2 "arm_float_rhs_operand" "")))]
1051169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT"
1052132718Skan  "
1053169689Skan  if (TARGET_MAVERICK)
1054132718Skan    {
1055132718Skan       if (!cirrus_fp_register (operands[1], DFmode))
1056132718Skan         operands[1] = force_reg (DFmode, operands[1]);
1057132718Skan       if (!cirrus_fp_register (operands[2], DFmode))
1058132718Skan         operands[2] = force_reg (DFmode, operands[2]);
1059132718Skan    }
1060132718Skan")
106190075Sobrien
106290075Sobrien
106390075Sobrien;; Multiplication insns
106490075Sobrien
106590075Sobrien(define_expand "mulsi3"
106690075Sobrien  [(set (match_operand:SI          0 "s_register_operand" "")
106790075Sobrien	(mult:SI (match_operand:SI 2 "s_register_operand" "")
106890075Sobrien		 (match_operand:SI 1 "s_register_operand" "")))]
106990075Sobrien  "TARGET_EITHER"
107090075Sobrien  ""
107190075Sobrien)
107290075Sobrien
107390075Sobrien;; Use `&' and then `0' to prevent the operands 0 and 1 being the same
107490075Sobrien(define_insn "*arm_mulsi3"
107590075Sobrien  [(set (match_operand:SI          0 "s_register_operand" "=&r,&r")
107690075Sobrien	(mult:SI (match_operand:SI 2 "s_register_operand" "r,r")
107790075Sobrien		 (match_operand:SI 1 "s_register_operand" "%?r,0")))]
107890075Sobrien  "TARGET_ARM"
107990075Sobrien  "mul%?\\t%0, %2, %1"
1080169689Skan  [(set_attr "insn" "mul")
108190075Sobrien   (set_attr "predicable" "yes")]
108290075Sobrien)
108390075Sobrien
108490075Sobrien; Unfortunately with the Thumb the '&'/'0' trick can fails when operands 
108590075Sobrien; 1 and 2; are the same, because reload will make operand 0 match 
108690075Sobrien; operand 1 without realizing that this conflicts with operand 2.  We fix 
108790075Sobrien; this by adding another alternative to match this case, and then `reload' 
108890075Sobrien; it ourselves.  This alternative must come first.
108990075Sobrien(define_insn "*thumb_mulsi3"
109090075Sobrien  [(set (match_operand:SI          0 "register_operand" "=&l,&l,&l")
109190075Sobrien	(mult:SI (match_operand:SI 1 "register_operand" "%l,*h,0")
109290075Sobrien		 (match_operand:SI 2 "register_operand" "l,l,l")))]
109390075Sobrien  "TARGET_THUMB"
109490075Sobrien  "*
109590075Sobrien  if (which_alternative < 2)
1096169689Skan    return \"mov\\t%0, %1\;mul\\t%0, %2\";
109790075Sobrien  else
1098169689Skan    return \"mul\\t%0, %2\";
109990075Sobrien  "
110090075Sobrien  [(set_attr "length" "4,4,2")
1101169689Skan   (set_attr "insn" "mul")]
110290075Sobrien)
110390075Sobrien
110490075Sobrien(define_insn "*mulsi3_compare0"
110590075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
110690075Sobrien	(compare:CC_NOOV (mult:SI
110790075Sobrien			  (match_operand:SI 2 "s_register_operand" "r,r")
110890075Sobrien			  (match_operand:SI 1 "s_register_operand" "%?r,0"))
110990075Sobrien			 (const_int 0)))
111090075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=&r,&r")
111190075Sobrien	(mult:SI (match_dup 2) (match_dup 1)))]
1112169689Skan  "TARGET_ARM"
111390075Sobrien  "mul%?s\\t%0, %2, %1"
111490075Sobrien  [(set_attr "conds" "set")
1115169689Skan   (set_attr "insn" "muls")]
111690075Sobrien)
111790075Sobrien
111890075Sobrien(define_insn "*mulsi_compare0_scratch"
111990075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
112090075Sobrien	(compare:CC_NOOV (mult:SI
112190075Sobrien			  (match_operand:SI 2 "s_register_operand" "r,r")
112290075Sobrien			  (match_operand:SI 1 "s_register_operand" "%?r,0"))
112390075Sobrien			 (const_int 0)))
112490075Sobrien   (clobber (match_scratch:SI 0 "=&r,&r"))]
1125169689Skan  "TARGET_ARM"
112690075Sobrien  "mul%?s\\t%0, %2, %1"
112790075Sobrien  [(set_attr "conds" "set")
1128169689Skan   (set_attr "insn" "muls")]
112990075Sobrien)
113090075Sobrien
113190075Sobrien;; Unnamed templates to match MLA instruction.
113290075Sobrien
113390075Sobrien(define_insn "*mulsi3addsi"
113490075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r,&r")
113590075Sobrien	(plus:SI
113690075Sobrien	  (mult:SI (match_operand:SI 2 "s_register_operand" "r,r,r,r")
113790075Sobrien		   (match_operand:SI 1 "s_register_operand" "%r,0,r,0"))
113890075Sobrien	  (match_operand:SI 3 "s_register_operand" "?r,r,0,0")))]
113990075Sobrien  "TARGET_ARM"
114090075Sobrien  "mla%?\\t%0, %2, %1, %3"
1141169689Skan  [(set_attr "insn" "mla")
114290075Sobrien   (set_attr "predicable" "yes")]
114390075Sobrien)
114490075Sobrien
114590075Sobrien(define_insn "*mulsi3addsi_compare0"
114690075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
114790075Sobrien	(compare:CC_NOOV
114890075Sobrien	 (plus:SI (mult:SI
114990075Sobrien		   (match_operand:SI 2 "s_register_operand" "r,r,r,r")
115090075Sobrien		   (match_operand:SI 1 "s_register_operand" "%r,0,r,0"))
115190075Sobrien		  (match_operand:SI 3 "s_register_operand" "?r,r,0,0"))
115290075Sobrien	 (const_int 0)))
115390075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r,&r")
115490075Sobrien	(plus:SI (mult:SI (match_dup 2) (match_dup 1))
115590075Sobrien		 (match_dup 3)))]
1156169689Skan  "TARGET_ARM"
115790075Sobrien  "mla%?s\\t%0, %2, %1, %3"
115890075Sobrien  [(set_attr "conds" "set")
1159169689Skan   (set_attr "insn" "mlas")]
116090075Sobrien)
116190075Sobrien
116290075Sobrien(define_insn "*mulsi3addsi_compare0_scratch"
116390075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
116490075Sobrien	(compare:CC_NOOV
116590075Sobrien	 (plus:SI (mult:SI
116690075Sobrien		   (match_operand:SI 2 "s_register_operand" "r,r,r,r")
116790075Sobrien		   (match_operand:SI 1 "s_register_operand" "%r,0,r,0"))
116890075Sobrien		  (match_operand:SI 3 "s_register_operand" "?r,r,0,0"))
116990075Sobrien	 (const_int 0)))
117090075Sobrien   (clobber (match_scratch:SI 0 "=&r,&r,&r,&r"))]
1171169689Skan  "TARGET_ARM"
117290075Sobrien  "mla%?s\\t%0, %2, %1, %3"
117390075Sobrien  [(set_attr "conds" "set")
1174169689Skan   (set_attr "insn" "mlas")]
117590075Sobrien)
117690075Sobrien
1177132718Skan;; Unnamed template to match long long multiply-accumulate (smlal)
117890075Sobrien
117990075Sobrien(define_insn "*mulsidi3adddi"
118090075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r")
118190075Sobrien	(plus:DI
118290075Sobrien	 (mult:DI
118390075Sobrien	  (sign_extend:DI (match_operand:SI 2 "s_register_operand" "%r"))
118490075Sobrien	  (sign_extend:DI (match_operand:SI 3 "s_register_operand" "r")))
118590075Sobrien	 (match_operand:DI 1 "s_register_operand" "0")))]
1186169689Skan  "TARGET_ARM && arm_arch3m"
118790075Sobrien  "smlal%?\\t%Q0, %R0, %3, %2"
1188169689Skan  [(set_attr "insn" "smlal")
118990075Sobrien   (set_attr "predicable" "yes")]
119090075Sobrien)
119190075Sobrien
119290075Sobrien(define_insn "mulsidi3"
119390075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r")
119490075Sobrien	(mult:DI
119590075Sobrien	 (sign_extend:DI (match_operand:SI 1 "s_register_operand" "%r"))
119690075Sobrien	 (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r"))))]
1197169689Skan  "TARGET_ARM && arm_arch3m"
119890075Sobrien  "smull%?\\t%Q0, %R0, %1, %2"
1199169689Skan  [(set_attr "insn" "smull")
120090075Sobrien   (set_attr "predicable" "yes")]
120190075Sobrien)
120290075Sobrien
120390075Sobrien(define_insn "umulsidi3"
120490075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r")
120590075Sobrien	(mult:DI
120690075Sobrien	 (zero_extend:DI (match_operand:SI 1 "s_register_operand" "%r"))
120790075Sobrien	 (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r"))))]
1208169689Skan  "TARGET_ARM && arm_arch3m"
120990075Sobrien  "umull%?\\t%Q0, %R0, %1, %2"
1210169689Skan  [(set_attr "insn" "umull")
121190075Sobrien   (set_attr "predicable" "yes")]
121290075Sobrien)
121390075Sobrien
1214132718Skan;; Unnamed template to match long long unsigned multiply-accumulate (umlal)
121590075Sobrien
121690075Sobrien(define_insn "*umulsidi3adddi"
121790075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r")
121890075Sobrien	(plus:DI
121990075Sobrien	 (mult:DI
122090075Sobrien	  (zero_extend:DI (match_operand:SI 2 "s_register_operand" "%r"))
122190075Sobrien	  (zero_extend:DI (match_operand:SI 3 "s_register_operand" "r")))
122290075Sobrien	 (match_operand:DI 1 "s_register_operand" "0")))]
1223169689Skan  "TARGET_ARM && arm_arch3m"
122490075Sobrien  "umlal%?\\t%Q0, %R0, %3, %2"
1225169689Skan  [(set_attr "insn" "umlal")
122690075Sobrien   (set_attr "predicable" "yes")]
122790075Sobrien)
122890075Sobrien
122990075Sobrien(define_insn "smulsi3_highpart"
123090075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=&r,&r")
123190075Sobrien	(truncate:SI
123290075Sobrien	 (lshiftrt:DI
123390075Sobrien	  (mult:DI
123490075Sobrien	   (sign_extend:DI (match_operand:SI 1 "s_register_operand" "%r,0"))
123590075Sobrien	   (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")))
123690075Sobrien	  (const_int 32))))
123790075Sobrien   (clobber (match_scratch:SI 3 "=&r,&r"))]
1238169689Skan  "TARGET_ARM && arm_arch3m"
123990075Sobrien  "smull%?\\t%3, %0, %2, %1"
1240169689Skan  [(set_attr "insn" "smull")
124190075Sobrien   (set_attr "predicable" "yes")]
124290075Sobrien)
124390075Sobrien
124490075Sobrien(define_insn "umulsi3_highpart"
124590075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=&r,&r")
124690075Sobrien	(truncate:SI
124790075Sobrien	 (lshiftrt:DI
124890075Sobrien	  (mult:DI
124990075Sobrien	   (zero_extend:DI (match_operand:SI 1 "s_register_operand" "%r,0"))
125090075Sobrien	   (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")))
125190075Sobrien	  (const_int 32))))
125290075Sobrien   (clobber (match_scratch:SI 3 "=&r,&r"))]
1253169689Skan  "TARGET_ARM && arm_arch3m"
125490075Sobrien  "umull%?\\t%3, %0, %2, %1"
1255169689Skan  [(set_attr "insn" "umull")
125690075Sobrien   (set_attr "predicable" "yes")]
125790075Sobrien)
125890075Sobrien
125990075Sobrien(define_insn "mulhisi3"
126090075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
126190075Sobrien	(mult:SI (sign_extend:SI
126290075Sobrien		  (match_operand:HI 1 "s_register_operand" "%r"))
126390075Sobrien		 (sign_extend:SI
126490075Sobrien		  (match_operand:HI 2 "s_register_operand" "r"))))]
1265132718Skan  "TARGET_ARM && arm_arch5e"
126690075Sobrien  "smulbb%?\\t%0, %1, %2"
1267169689Skan  [(set_attr "insn" "smulxy")
1268132718Skan   (set_attr "predicable" "yes")]
126990075Sobrien)
127090075Sobrien
1271132718Skan(define_insn "*mulhisi3tb"
1272132718Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
1273132718Skan	(mult:SI (ashiftrt:SI
1274132718Skan		  (match_operand:SI 1 "s_register_operand" "r")
1275132718Skan		  (const_int 16))
1276132718Skan		 (sign_extend:SI
1277132718Skan		  (match_operand:HI 2 "s_register_operand" "r"))))]
1278132718Skan  "TARGET_ARM && arm_arch5e"
1279132718Skan  "smultb%?\\t%0, %1, %2"
1280169689Skan  [(set_attr "insn" "smulxy")
1281132718Skan   (set_attr "predicable" "yes")]
1282132718Skan)
1283132718Skan
1284132718Skan(define_insn "*mulhisi3bt"
1285132718Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
1286132718Skan	(mult:SI (sign_extend:SI
1287132718Skan		  (match_operand:HI 1 "s_register_operand" "r"))
1288132718Skan		 (ashiftrt:SI
1289132718Skan		  (match_operand:SI 2 "s_register_operand" "r")
1290132718Skan		  (const_int 16))))]
1291132718Skan  "TARGET_ARM && arm_arch5e"
1292132718Skan  "smulbt%?\\t%0, %1, %2"
1293169689Skan  [(set_attr "insn" "smulxy")
1294132718Skan   (set_attr "predicable" "yes")]
1295132718Skan)
1296132718Skan
1297132718Skan(define_insn "*mulhisi3tt"
1298132718Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
1299132718Skan	(mult:SI (ashiftrt:SI
1300132718Skan		  (match_operand:SI 1 "s_register_operand" "r")
1301132718Skan		  (const_int 16))
1302132718Skan		 (ashiftrt:SI
1303132718Skan		  (match_operand:SI 2 "s_register_operand" "r")
1304132718Skan		  (const_int 16))))]
1305132718Skan  "TARGET_ARM && arm_arch5e"
1306132718Skan  "smultt%?\\t%0, %1, %2"
1307169689Skan  [(set_attr "insn" "smulxy")
1308132718Skan   (set_attr "predicable" "yes")]
1309132718Skan)
1310132718Skan
131190075Sobrien(define_insn "*mulhisi3addsi"
131290075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
131390075Sobrien	(plus:SI (match_operand:SI 1 "s_register_operand" "r")
131490075Sobrien		 (mult:SI (sign_extend:SI
131590075Sobrien			   (match_operand:HI 2 "s_register_operand" "%r"))
131690075Sobrien			  (sign_extend:SI
131790075Sobrien			   (match_operand:HI 3 "s_register_operand" "r")))))]
1318132718Skan  "TARGET_ARM && arm_arch5e"
131990075Sobrien  "smlabb%?\\t%0, %2, %3, %1"
1320169689Skan  [(set_attr "insn" "smlaxy")
1321132718Skan   (set_attr "predicable" "yes")]
132290075Sobrien)
132390075Sobrien
132490075Sobrien(define_insn "*mulhidi3adddi"
132590075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=r")
132690075Sobrien	(plus:DI
132790075Sobrien	  (match_operand:DI 1 "s_register_operand" "0")
132890075Sobrien	  (mult:DI (sign_extend:DI
132990075Sobrien	 	    (match_operand:HI 2 "s_register_operand" "%r"))
133090075Sobrien		   (sign_extend:DI
133190075Sobrien		    (match_operand:HI 3 "s_register_operand" "r")))))]
1332132718Skan  "TARGET_ARM && arm_arch5e"
133390075Sobrien  "smlalbb%?\\t%Q0, %R0, %2, %3"
1334169689Skan  [(set_attr "insn" "smlalxy")
1335132718Skan   (set_attr "predicable" "yes")])
133690075Sobrien
1337132718Skan(define_expand "mulsf3"
1338132718Skan  [(set (match_operand:SF          0 "s_register_operand" "")
1339132718Skan	(mult:SF (match_operand:SF 1 "s_register_operand" "")
1340169689Skan		 (match_operand:SF 2 "arm_float_rhs_operand" "")))]
1341169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT"
1342132718Skan  "
1343169689Skan  if (TARGET_MAVERICK
1344132718Skan      && !cirrus_fp_register (operands[2], SFmode))
1345132718Skan    operands[2] = force_reg (SFmode, operands[2]);
1346132718Skan")
134790075Sobrien
1348132718Skan(define_expand "muldf3"
1349132718Skan  [(set (match_operand:DF          0 "s_register_operand" "")
1350132718Skan	(mult:DF (match_operand:DF 1 "s_register_operand" "")
1351169689Skan		 (match_operand:DF 2 "arm_float_rhs_operand" "")))]
1352169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT"
1353132718Skan  "
1354169689Skan  if (TARGET_MAVERICK
1355132718Skan      && !cirrus_fp_register (operands[2], DFmode))
1356132718Skan    operands[2] = force_reg (DFmode, operands[2]);
1357132718Skan")
135890075Sobrien
135990075Sobrien;; Division insns
136090075Sobrien
1361132718Skan(define_expand "divsf3"
1362132718Skan  [(set (match_operand:SF 0 "s_register_operand" "")
1363169689Skan	(div:SF (match_operand:SF 1 "arm_float_rhs_operand" "")
1364169689Skan		(match_operand:SF 2 "arm_float_rhs_operand" "")))]
1365169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
1366132718Skan  "")
136790075Sobrien
1368132718Skan(define_expand "divdf3"
1369132718Skan  [(set (match_operand:DF 0 "s_register_operand" "")
1370169689Skan	(div:DF (match_operand:DF 1 "arm_float_rhs_operand" "")
1371169689Skan		(match_operand:DF 2 "arm_float_rhs_operand" "")))]
1372169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
1373132718Skan  "")
137490075Sobrien
137590075Sobrien;; Modulo insns
137690075Sobrien
1377132718Skan(define_expand "modsf3"
1378132718Skan  [(set (match_operand:SF 0 "s_register_operand" "")
1379132718Skan	(mod:SF (match_operand:SF 1 "s_register_operand" "")
1380169689Skan		(match_operand:SF 2 "arm_float_rhs_operand" "")))]
1381169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
1382132718Skan  "")
138390075Sobrien
1384132718Skan(define_expand "moddf3"
1385132718Skan  [(set (match_operand:DF 0 "s_register_operand" "")
1386132718Skan	(mod:DF (match_operand:DF 1 "s_register_operand" "")
1387169689Skan		(match_operand:DF 2 "arm_float_rhs_operand" "")))]
1388169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
1389132718Skan  "")
139090075Sobrien
139190075Sobrien;; Boolean and,ior,xor insns
139290075Sobrien
139390075Sobrien;; Split up double word logical operations
139490075Sobrien
139590075Sobrien;; Split up simple DImode logical operations.  Simply perform the logical
139690075Sobrien;; operation on the upper and lower halves of the registers.
139790075Sobrien(define_split
139890075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "")
139990075Sobrien	(match_operator:DI 6 "logical_binary_operator"
140090075Sobrien	  [(match_operand:DI 1 "s_register_operand" "")
140190075Sobrien	   (match_operand:DI 2 "s_register_operand" "")]))]
1402132718Skan  "TARGET_ARM && reload_completed && ! IS_IWMMXT_REGNUM (REGNO (operands[0]))"
140390075Sobrien  [(set (match_dup 0) (match_op_dup:SI 6 [(match_dup 1) (match_dup 2)]))
140490075Sobrien   (set (match_dup 3) (match_op_dup:SI 6 [(match_dup 4) (match_dup 5)]))]
140590075Sobrien  "
140690075Sobrien  {
140790075Sobrien    operands[3] = gen_highpart (SImode, operands[0]);
140890075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
140990075Sobrien    operands[4] = gen_highpart (SImode, operands[1]);
141090075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
141190075Sobrien    operands[5] = gen_highpart (SImode, operands[2]);
141290075Sobrien    operands[2] = gen_lowpart (SImode, operands[2]);
141390075Sobrien  }"
141490075Sobrien)
141590075Sobrien
141690075Sobrien(define_split
141790075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "")
141890075Sobrien	(match_operator:DI 6 "logical_binary_operator"
141990075Sobrien	  [(sign_extend:DI (match_operand:SI 2 "s_register_operand" ""))
142090075Sobrien	   (match_operand:DI 1 "s_register_operand" "")]))]
142190075Sobrien  "TARGET_ARM && reload_completed"
142290075Sobrien  [(set (match_dup 0) (match_op_dup:SI 6 [(match_dup 1) (match_dup 2)]))
142390075Sobrien   (set (match_dup 3) (match_op_dup:SI 6
142490075Sobrien			[(ashiftrt:SI (match_dup 2) (const_int 31))
142590075Sobrien			 (match_dup 4)]))]
142690075Sobrien  "
142790075Sobrien  {
142890075Sobrien    operands[3] = gen_highpart (SImode, operands[0]);
142990075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
143090075Sobrien    operands[4] = gen_highpart (SImode, operands[1]);
143190075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
143290075Sobrien    operands[5] = gen_highpart (SImode, operands[2]);
143390075Sobrien    operands[2] = gen_lowpart (SImode, operands[2]);
143490075Sobrien  }"
143590075Sobrien)
143690075Sobrien
143790075Sobrien;; The zero extend of operand 2 means we can just copy the high part of
143890075Sobrien;; operand1 into operand0.
143990075Sobrien(define_split
144090075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "")
144190075Sobrien	(ior:DI
144290075Sobrien	  (zero_extend:DI (match_operand:SI 2 "s_register_operand" ""))
144390075Sobrien	  (match_operand:DI 1 "s_register_operand" "")))]
144490075Sobrien  "TARGET_ARM && operands[0] != operands[1] && reload_completed"
144590075Sobrien  [(set (match_dup 0) (ior:SI (match_dup 1) (match_dup 2)))
144690075Sobrien   (set (match_dup 3) (match_dup 4))]
144790075Sobrien  "
144890075Sobrien  {
144990075Sobrien    operands[4] = gen_highpart (SImode, operands[1]);
145090075Sobrien    operands[3] = gen_highpart (SImode, operands[0]);
145190075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
145290075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
145390075Sobrien  }"
145490075Sobrien)
145590075Sobrien
145690075Sobrien;; The zero extend of operand 2 means we can just copy the high part of
145790075Sobrien;; operand1 into operand0.
145890075Sobrien(define_split
145990075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "")
146090075Sobrien	(xor:DI
146190075Sobrien	  (zero_extend:DI (match_operand:SI 2 "s_register_operand" ""))
146290075Sobrien	  (match_operand:DI 1 "s_register_operand" "")))]
146390075Sobrien  "TARGET_ARM && operands[0] != operands[1] && reload_completed"
146490075Sobrien  [(set (match_dup 0) (xor:SI (match_dup 1) (match_dup 2)))
146590075Sobrien   (set (match_dup 3) (match_dup 4))]
146690075Sobrien  "
146790075Sobrien  {
146890075Sobrien    operands[4] = gen_highpart (SImode, operands[1]);
146990075Sobrien    operands[3] = gen_highpart (SImode, operands[0]);
147090075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
147190075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
147290075Sobrien  }"
147390075Sobrien)
147490075Sobrien
147590075Sobrien(define_insn "anddi3"
147690075Sobrien  [(set (match_operand:DI         0 "s_register_operand" "=&r,&r")
147790075Sobrien	(and:DI (match_operand:DI 1 "s_register_operand"  "%0,r")
147890075Sobrien		(match_operand:DI 2 "s_register_operand"   "r,r")))]
1479132718Skan  "TARGET_ARM && ! TARGET_IWMMXT"
148090075Sobrien  "#"
148190075Sobrien  [(set_attr "length" "8")]
148290075Sobrien)
148390075Sobrien
148490075Sobrien(define_insn_and_split "*anddi_zesidi_di"
148590075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
148690075Sobrien	(and:DI (zero_extend:DI
148790075Sobrien		 (match_operand:SI 2 "s_register_operand" "r,r"))
148890075Sobrien		(match_operand:DI 1 "s_register_operand" "?r,0")))]
148990075Sobrien  "TARGET_ARM"
149090075Sobrien  "#"
149190075Sobrien  "TARGET_ARM && reload_completed"
149290075Sobrien  ; The zero extend of operand 2 clears the high word of the output
149390075Sobrien  ; operand.
149490075Sobrien  [(set (match_dup 0) (and:SI (match_dup 1) (match_dup 2)))
149590075Sobrien   (set (match_dup 3) (const_int 0))]
149690075Sobrien  "
149790075Sobrien  {
149890075Sobrien    operands[3] = gen_highpart (SImode, operands[0]);
149990075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
150090075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
150190075Sobrien  }"
150290075Sobrien  [(set_attr "length" "8")]
150390075Sobrien)
150490075Sobrien
150590075Sobrien(define_insn "*anddi_sesdi_di"
150690075Sobrien  [(set (match_operand:DI          0 "s_register_operand" "=&r,&r")
150790075Sobrien	(and:DI (sign_extend:DI
150890075Sobrien		 (match_operand:SI 2 "s_register_operand" "r,r"))
150990075Sobrien		(match_operand:DI  1 "s_register_operand" "?r,0")))]
151090075Sobrien  "TARGET_ARM"
151190075Sobrien  "#"
151290075Sobrien  [(set_attr "length" "8")]
151390075Sobrien)
151490075Sobrien
151590075Sobrien(define_expand "andsi3"
151690075Sobrien  [(set (match_operand:SI         0 "s_register_operand" "")
151790075Sobrien	(and:SI (match_operand:SI 1 "s_register_operand" "")
151890075Sobrien		(match_operand:SI 2 "reg_or_int_operand" "")))]
151990075Sobrien  "TARGET_EITHER"
152090075Sobrien  "
152190075Sobrien  if (TARGET_ARM)
152290075Sobrien    {
152390075Sobrien      if (GET_CODE (operands[2]) == CONST_INT)
152490075Sobrien        {
1525169689Skan          arm_split_constant (AND, SImode, NULL_RTX,
1526169689Skan	                      INTVAL (operands[2]), operands[0],
1527169689Skan			      operands[1], optimize && !no_new_pseudos);
1528169689Skan
152990075Sobrien          DONE;
153090075Sobrien        }
153190075Sobrien    }
153290075Sobrien  else /* TARGET_THUMB */
153390075Sobrien    {
153490075Sobrien      if (GET_CODE (operands[2]) != CONST_INT)
153590075Sobrien        operands[2] = force_reg (SImode, operands[2]);
153690075Sobrien      else
153790075Sobrien        {
153890075Sobrien          int i;
153990075Sobrien	  
154090075Sobrien          if (((unsigned HOST_WIDE_INT) ~INTVAL (operands[2])) < 256)
154190075Sobrien  	    {
154290075Sobrien	      operands[2] = force_reg (SImode,
154390075Sobrien				       GEN_INT (~INTVAL (operands[2])));
154490075Sobrien	      
154590075Sobrien	      emit_insn (gen_bicsi3 (operands[0], operands[2], operands[1]));
154690075Sobrien	      
154790075Sobrien	      DONE;
154890075Sobrien	    }
154990075Sobrien
155090075Sobrien          for (i = 9; i <= 31; i++)
155190075Sobrien	    {
155290075Sobrien	      if ((((HOST_WIDE_INT) 1) << i) - 1 == INTVAL (operands[2]))
155390075Sobrien	        {
155490075Sobrien	          emit_insn (gen_extzv (operands[0], operands[1], GEN_INT (i),
155590075Sobrien			 	        const0_rtx));
155690075Sobrien	          DONE;
155790075Sobrien	        }
155890075Sobrien	      else if ((((HOST_WIDE_INT) 1) << i) - 1
155990075Sobrien		       == ~INTVAL (operands[2]))
156090075Sobrien	        {
156190075Sobrien	          rtx shift = GEN_INT (i);
156290075Sobrien	          rtx reg = gen_reg_rtx (SImode);
156390075Sobrien		
156490075Sobrien	          emit_insn (gen_lshrsi3 (reg, operands[1], shift));
156590075Sobrien	          emit_insn (gen_ashlsi3 (operands[0], reg, shift));
156690075Sobrien		  
156790075Sobrien	          DONE;
156890075Sobrien	        }
156990075Sobrien	    }
157090075Sobrien
157190075Sobrien          operands[2] = force_reg (SImode, operands[2]);
157290075Sobrien        }
157390075Sobrien    }
157490075Sobrien  "
157590075Sobrien)
157690075Sobrien
157790075Sobrien(define_insn_and_split "*arm_andsi3_insn"
157890075Sobrien  [(set (match_operand:SI         0 "s_register_operand" "=r,r,r")
157990075Sobrien	(and:SI (match_operand:SI 1 "s_register_operand" "r,r,r")
158090075Sobrien		(match_operand:SI 2 "reg_or_int_operand" "rI,K,?n")))]
158190075Sobrien  "TARGET_ARM"
158290075Sobrien  "@
158390075Sobrien   and%?\\t%0, %1, %2
158490075Sobrien   bic%?\\t%0, %1, #%B2
158590075Sobrien   #"
158690075Sobrien  "TARGET_ARM
158790075Sobrien   && GET_CODE (operands[2]) == CONST_INT
158890075Sobrien   && !(const_ok_for_arm (INTVAL (operands[2]))
158990075Sobrien	|| const_ok_for_arm (~INTVAL (operands[2])))"
159090075Sobrien  [(clobber (const_int 0))]
159190075Sobrien  "
1592169689Skan  arm_split_constant  (AND, SImode, curr_insn, 
1593169689Skan	               INTVAL (operands[2]), operands[0], operands[1], 0);
159490075Sobrien  DONE;
159590075Sobrien  "
159690075Sobrien  [(set_attr "length" "4,4,16")
159790075Sobrien   (set_attr "predicable" "yes")]
159890075Sobrien)
159990075Sobrien
160090075Sobrien(define_insn "*thumb_andsi3_insn"
160190075Sobrien  [(set (match_operand:SI         0 "register_operand" "=l")
160290075Sobrien	(and:SI (match_operand:SI 1 "register_operand" "%0")
160390075Sobrien		(match_operand:SI 2 "register_operand" "l")))]
160490075Sobrien  "TARGET_THUMB"
160590075Sobrien  "and\\t%0, %0, %2"
160690075Sobrien  [(set_attr "length" "2")]
160790075Sobrien)
160890075Sobrien
160990075Sobrien(define_insn "*andsi3_compare0"
161090075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
161190075Sobrien	(compare:CC_NOOV
161290075Sobrien	 (and:SI (match_operand:SI 1 "s_register_operand" "r,r")
161390075Sobrien		 (match_operand:SI 2 "arm_not_operand" "rI,K"))
161490075Sobrien	 (const_int 0)))
161590075Sobrien   (set (match_operand:SI          0 "s_register_operand" "=r,r")
161690075Sobrien	(and:SI (match_dup 1) (match_dup 2)))]
161790075Sobrien  "TARGET_ARM"
161890075Sobrien  "@
161990075Sobrien   and%?s\\t%0, %1, %2
162090075Sobrien   bic%?s\\t%0, %1, #%B2"
162190075Sobrien  [(set_attr "conds" "set")]
162290075Sobrien)
162390075Sobrien
162490075Sobrien(define_insn "*andsi3_compare0_scratch"
162590075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
162690075Sobrien	(compare:CC_NOOV
162790075Sobrien	 (and:SI (match_operand:SI 0 "s_register_operand" "r,r")
162890075Sobrien		 (match_operand:SI 1 "arm_not_operand" "rI,K"))
162990075Sobrien	 (const_int 0)))
163090075Sobrien   (clobber (match_scratch:SI 2 "=X,r"))]
163190075Sobrien  "TARGET_ARM"
163290075Sobrien  "@
163390075Sobrien   tst%?\\t%0, %1
163490075Sobrien   bic%?s\\t%2, %0, #%B1"
163590075Sobrien  [(set_attr "conds" "set")]
163690075Sobrien)
163790075Sobrien
163890075Sobrien(define_insn "*zeroextractsi_compare0_scratch"
163990075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
164090075Sobrien	(compare:CC_NOOV (zero_extract:SI
164190075Sobrien			  (match_operand:SI 0 "s_register_operand" "r")
164290075Sobrien		 	  (match_operand 1 "const_int_operand" "n")
164390075Sobrien			  (match_operand 2 "const_int_operand" "n"))
164490075Sobrien			 (const_int 0)))]
164590075Sobrien  "TARGET_ARM
164690075Sobrien  && (INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) < 32
164790075Sobrien      && INTVAL (operands[1]) > 0 
164890075Sobrien      && INTVAL (operands[1]) + (INTVAL (operands[2]) & 1) <= 8
164990075Sobrien      && INTVAL (operands[1]) + INTVAL (operands[2]) <= 32)"
165090075Sobrien  "*
165190075Sobrien  operands[1] = GEN_INT (((1 << INTVAL (operands[1])) - 1)
165290075Sobrien			 << INTVAL (operands[2]));
165390075Sobrien  output_asm_insn (\"tst%?\\t%0, %1\", operands);
165490075Sobrien  return \"\";
165590075Sobrien  "
165690075Sobrien  [(set_attr "conds" "set")]
165790075Sobrien)
165890075Sobrien
1659169689Skan(define_insn_and_split "*ne_zeroextractsi"
166090075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
166190075Sobrien	(ne:SI (zero_extract:SI
166290075Sobrien		(match_operand:SI 1 "s_register_operand" "r")
166390075Sobrien		(match_operand:SI 2 "const_int_operand" "n")
166490075Sobrien		(match_operand:SI 3 "const_int_operand" "n"))
1665104752Skan	       (const_int 0)))
1666104752Skan   (clobber (reg:CC CC_REGNUM))]
166790075Sobrien  "TARGET_ARM
166890075Sobrien   && (INTVAL (operands[3]) >= 0 && INTVAL (operands[3]) < 32
166990075Sobrien       && INTVAL (operands[2]) > 0 
167090075Sobrien       && INTVAL (operands[2]) + (INTVAL (operands[3]) & 1) <= 8
167190075Sobrien       && INTVAL (operands[2]) + INTVAL (operands[3]) <= 32)"
1672169689Skan  "#"
1673169689Skan  "TARGET_ARM
1674169689Skan   && (INTVAL (operands[3]) >= 0 && INTVAL (operands[3]) < 32
1675169689Skan       && INTVAL (operands[2]) > 0 
1676169689Skan       && INTVAL (operands[2]) + (INTVAL (operands[3]) & 1) <= 8
1677169689Skan       && INTVAL (operands[2]) + INTVAL (operands[3]) <= 32)"
1678169689Skan  [(parallel [(set (reg:CC_NOOV CC_REGNUM)
1679169689Skan		   (compare:CC_NOOV (and:SI (match_dup 1) (match_dup 2))
1680169689Skan				    (const_int 0)))
1681169689Skan	      (set (match_dup 0) (and:SI (match_dup 1) (match_dup 2)))])
1682169689Skan   (set (match_dup 0)
1683169689Skan	(if_then_else:SI (eq (reg:CC_NOOV CC_REGNUM) (const_int 0))
1684169689Skan			 (match_dup 0) (const_int 1)))]
1685169689Skan  "
168690075Sobrien  operands[2] = GEN_INT (((1 << INTVAL (operands[2])) - 1)
1687169689Skan			 << INTVAL (operands[3])); 
168890075Sobrien  "
168990075Sobrien  [(set_attr "conds" "clob")
169090075Sobrien   (set_attr "length" "8")]
169190075Sobrien)
169290075Sobrien
1693169689Skan(define_insn_and_split "*ne_zeroextractsi_shifted"
1694169689Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
1695169689Skan	(ne:SI (zero_extract:SI
1696169689Skan		(match_operand:SI 1 "s_register_operand" "r")
1697169689Skan		(match_operand:SI 2 "const_int_operand" "n")
1698169689Skan		(const_int 0))
1699169689Skan	       (const_int 0)))
1700169689Skan   (clobber (reg:CC CC_REGNUM))]
1701169689Skan  "TARGET_ARM"
1702169689Skan  "#"
1703169689Skan  "TARGET_ARM"
1704169689Skan  [(parallel [(set (reg:CC_NOOV CC_REGNUM)
1705169689Skan		   (compare:CC_NOOV (ashift:SI (match_dup 1) (match_dup 2))
1706169689Skan				    (const_int 0)))
1707169689Skan	      (set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))])
1708169689Skan   (set (match_dup 0)
1709169689Skan	(if_then_else:SI (eq (reg:CC_NOOV CC_REGNUM) (const_int 0))
1710169689Skan			 (match_dup 0) (const_int 1)))]
1711169689Skan  "
1712169689Skan  operands[2] = GEN_INT (32 - INTVAL (operands[2]));
1713169689Skan  "
1714169689Skan  [(set_attr "conds" "clob")
1715169689Skan   (set_attr "length" "8")]
1716169689Skan)
1717169689Skan
1718169689Skan(define_insn_and_split "*ite_ne_zeroextractsi"
1719169689Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
1720169689Skan	(if_then_else:SI (ne (zero_extract:SI
1721169689Skan			      (match_operand:SI 1 "s_register_operand" "r")
1722169689Skan			      (match_operand:SI 2 "const_int_operand" "n")
1723169689Skan			      (match_operand:SI 3 "const_int_operand" "n"))
1724169689Skan			     (const_int 0))
1725169689Skan			 (match_operand:SI 4 "arm_not_operand" "rIK")
1726169689Skan			 (const_int 0)))
1727169689Skan   (clobber (reg:CC CC_REGNUM))]
1728169689Skan  "TARGET_ARM
1729169689Skan   && (INTVAL (operands[3]) >= 0 && INTVAL (operands[3]) < 32
1730169689Skan       && INTVAL (operands[2]) > 0 
1731169689Skan       && INTVAL (operands[2]) + (INTVAL (operands[3]) & 1) <= 8
1732169689Skan       && INTVAL (operands[2]) + INTVAL (operands[3]) <= 32)
1733169689Skan   && !reg_overlap_mentioned_p (operands[0], operands[4])"
1734169689Skan  "#"
1735169689Skan  "TARGET_ARM
1736169689Skan   && (INTVAL (operands[3]) >= 0 && INTVAL (operands[3]) < 32
1737169689Skan       && INTVAL (operands[2]) > 0 
1738169689Skan       && INTVAL (operands[2]) + (INTVAL (operands[3]) & 1) <= 8
1739169689Skan       && INTVAL (operands[2]) + INTVAL (operands[3]) <= 32)
1740169689Skan   && !reg_overlap_mentioned_p (operands[0], operands[4])"
1741169689Skan  [(parallel [(set (reg:CC_NOOV CC_REGNUM)
1742169689Skan		   (compare:CC_NOOV (and:SI (match_dup 1) (match_dup 2))
1743169689Skan				    (const_int 0)))
1744169689Skan	      (set (match_dup 0) (and:SI (match_dup 1) (match_dup 2)))])
1745169689Skan   (set (match_dup 0)
1746169689Skan	(if_then_else:SI (eq (reg:CC_NOOV CC_REGNUM) (const_int 0))
1747169689Skan			 (match_dup 0) (match_dup 4)))]
1748169689Skan  "
1749169689Skan  operands[2] = GEN_INT (((1 << INTVAL (operands[2])) - 1)
1750169689Skan			 << INTVAL (operands[3])); 
1751169689Skan  "
1752169689Skan  [(set_attr "conds" "clob")
1753169689Skan   (set_attr "length" "8")]
1754169689Skan)
1755169689Skan
1756169689Skan(define_insn_and_split "*ite_ne_zeroextractsi_shifted"
1757169689Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
1758169689Skan	(if_then_else:SI (ne (zero_extract:SI
1759169689Skan			      (match_operand:SI 1 "s_register_operand" "r")
1760169689Skan			      (match_operand:SI 2 "const_int_operand" "n")
1761169689Skan			      (const_int 0))
1762169689Skan			     (const_int 0))
1763169689Skan			 (match_operand:SI 3 "arm_not_operand" "rIK")
1764169689Skan			 (const_int 0)))
1765169689Skan   (clobber (reg:CC CC_REGNUM))]
1766169689Skan  "TARGET_ARM && !reg_overlap_mentioned_p (operands[0], operands[3])"
1767169689Skan  "#"
1768169689Skan  "TARGET_ARM && !reg_overlap_mentioned_p (operands[0], operands[3])"
1769169689Skan  [(parallel [(set (reg:CC_NOOV CC_REGNUM)
1770169689Skan		   (compare:CC_NOOV (ashift:SI (match_dup 1) (match_dup 2))
1771169689Skan				    (const_int 0)))
1772169689Skan	      (set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))])
1773169689Skan   (set (match_dup 0)
1774169689Skan	(if_then_else:SI (eq (reg:CC_NOOV CC_REGNUM) (const_int 0))
1775169689Skan			 (match_dup 0) (match_dup 3)))]
1776169689Skan  "
1777169689Skan  operands[2] = GEN_INT (32 - INTVAL (operands[2]));
1778169689Skan  "
1779169689Skan  [(set_attr "conds" "clob")
1780169689Skan   (set_attr "length" "8")]
1781169689Skan)
1782169689Skan
1783132718Skan(define_split
1784132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
1785132718Skan	(zero_extract:SI (match_operand:SI 1 "s_register_operand" "")
1786132718Skan			 (match_operand:SI 2 "const_int_operand" "")
1787132718Skan			 (match_operand:SI 3 "const_int_operand" "")))
1788132718Skan   (clobber (match_operand:SI 4 "s_register_operand" ""))]
1789132718Skan  "TARGET_THUMB"
1790132718Skan  [(set (match_dup 4) (ashift:SI (match_dup 1) (match_dup 2)))
1791132718Skan   (set (match_dup 0) (lshiftrt:SI (match_dup 4) (match_dup 3)))]
1792132718Skan  "{
1793132718Skan     HOST_WIDE_INT temp = INTVAL (operands[2]);
1794132718Skan
1795132718Skan     operands[2] = GEN_INT (32 - temp - INTVAL (operands[3]));
1796132718Skan     operands[3] = GEN_INT (32 - temp);
1797132718Skan   }"
1798132718Skan)
1799132718Skan
1800132718Skan(define_split
1801132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
1802132718Skan	(match_operator:SI 1 "shiftable_operator"
1803132718Skan	 [(zero_extract:SI (match_operand:SI 2 "s_register_operand" "")
1804132718Skan			   (match_operand:SI 3 "const_int_operand" "")
1805132718Skan			   (match_operand:SI 4 "const_int_operand" ""))
1806132718Skan	  (match_operand:SI 5 "s_register_operand" "")]))
1807132718Skan   (clobber (match_operand:SI 6 "s_register_operand" ""))]
1808132718Skan  "TARGET_ARM"
1809132718Skan  [(set (match_dup 6) (ashift:SI (match_dup 2) (match_dup 3)))
1810132718Skan   (set (match_dup 0)
1811132718Skan	(match_op_dup 1
1812132718Skan	 [(lshiftrt:SI (match_dup 6) (match_dup 4))
1813132718Skan	  (match_dup 5)]))]
1814132718Skan  "{
1815132718Skan     HOST_WIDE_INT temp = INTVAL (operands[3]);
1816132718Skan
1817132718Skan     operands[3] = GEN_INT (32 - temp - INTVAL (operands[4]));
1818132718Skan     operands[4] = GEN_INT (32 - temp);
1819132718Skan   }"
1820132718Skan)
1821132718Skan  
1822132718Skan(define_split
1823132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
1824132718Skan	(sign_extract:SI (match_operand:SI 1 "s_register_operand" "")
1825132718Skan			 (match_operand:SI 2 "const_int_operand" "")
1826132718Skan			 (match_operand:SI 3 "const_int_operand" "")))]
1827132718Skan  "TARGET_THUMB"
1828132718Skan  [(set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))
1829132718Skan   (set (match_dup 0) (ashiftrt:SI (match_dup 0) (match_dup 3)))]
1830132718Skan  "{
1831132718Skan     HOST_WIDE_INT temp = INTVAL (operands[2]);
1832132718Skan
1833132718Skan     operands[2] = GEN_INT (32 - temp - INTVAL (operands[3]));
1834132718Skan     operands[3] = GEN_INT (32 - temp);
1835132718Skan   }"
1836132718Skan)
1837132718Skan
1838132718Skan(define_split
1839132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
1840132718Skan	(match_operator:SI 1 "shiftable_operator"
1841132718Skan	 [(sign_extract:SI (match_operand:SI 2 "s_register_operand" "")
1842132718Skan			   (match_operand:SI 3 "const_int_operand" "")
1843132718Skan			   (match_operand:SI 4 "const_int_operand" ""))
1844132718Skan	  (match_operand:SI 5 "s_register_operand" "")]))
1845132718Skan   (clobber (match_operand:SI 6 "s_register_operand" ""))]
1846132718Skan  "TARGET_ARM"
1847132718Skan  [(set (match_dup 6) (ashift:SI (match_dup 2) (match_dup 3)))
1848132718Skan   (set (match_dup 0)
1849132718Skan	(match_op_dup 1
1850132718Skan	 [(ashiftrt:SI (match_dup 6) (match_dup 4))
1851132718Skan	  (match_dup 5)]))]
1852132718Skan  "{
1853132718Skan     HOST_WIDE_INT temp = INTVAL (operands[3]);
1854132718Skan
1855132718Skan     operands[3] = GEN_INT (32 - temp - INTVAL (operands[4]));
1856132718Skan     operands[4] = GEN_INT (32 - temp);
1857132718Skan   }"
1858132718Skan)
1859132718Skan  
186090075Sobrien;;; ??? This pattern is bogus.  If operand3 has bits outside the range
186190075Sobrien;;; represented by the bitfield, then this will produce incorrect results.
186290075Sobrien;;; Somewhere, the value needs to be truncated.  On targets like the m68k,
1863117395Skan;;; which have a real bit-field insert instruction, the truncation happens
1864117395Skan;;; in the bit-field insert instruction itself.  Since arm does not have a
1865117395Skan;;; bit-field insert instruction, we would have to emit code here to truncate
186690075Sobrien;;; the value before we insert.  This loses some of the advantage of having
186790075Sobrien;;; this insv pattern, so this pattern needs to be reevalutated.
186890075Sobrien
186990075Sobrien(define_expand "insv"
187090075Sobrien  [(set (zero_extract:SI (match_operand:SI 0 "s_register_operand" "")
187190075Sobrien                         (match_operand:SI 1 "general_operand" "")
187290075Sobrien                         (match_operand:SI 2 "general_operand" ""))
1873117395Skan        (match_operand:SI 3 "reg_or_int_operand" ""))]
187490075Sobrien  "TARGET_ARM"
187590075Sobrien  "
187690075Sobrien  {
187790075Sobrien    int start_bit = INTVAL (operands[2]);
187890075Sobrien    int width = INTVAL (operands[1]);
187990075Sobrien    HOST_WIDE_INT mask = (((HOST_WIDE_INT)1) << width) - 1;
188090075Sobrien    rtx target, subtarget;
188190075Sobrien
188290075Sobrien    target = operands[0];
188390075Sobrien    /* Avoid using a subreg as a subtarget, and avoid writing a paradoxical 
188490075Sobrien       subreg as the final target.  */
188590075Sobrien    if (GET_CODE (target) == SUBREG)
188690075Sobrien      {
188790075Sobrien	subtarget = gen_reg_rtx (SImode);
188890075Sobrien	if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (target)))
188990075Sobrien	    < GET_MODE_SIZE (SImode))
189090075Sobrien	  target = SUBREG_REG (target);
189190075Sobrien      }
189290075Sobrien    else
189390075Sobrien      subtarget = target;    
189490075Sobrien
189590075Sobrien    if (GET_CODE (operands[3]) == CONST_INT)
189690075Sobrien      {
189790075Sobrien	/* Since we are inserting a known constant, we may be able to
189890075Sobrien	   reduce the number of bits that we have to clear so that
189990075Sobrien	   the mask becomes simple.  */
190090075Sobrien	/* ??? This code does not check to see if the new mask is actually
190190075Sobrien	   simpler.  It may not be.  */
190290075Sobrien	rtx op1 = gen_reg_rtx (SImode);
190390075Sobrien	/* ??? Truncate operand3 to fit in the bitfield.  See comment before
190490075Sobrien	   start of this pattern.  */
190590075Sobrien	HOST_WIDE_INT op3_value = mask & INTVAL (operands[3]);
190690075Sobrien	HOST_WIDE_INT mask2 = ((mask & ~op3_value) << start_bit);
190790075Sobrien
1908169689Skan	emit_insn (gen_andsi3 (op1, operands[0],
1909169689Skan			       gen_int_mode (~mask2, SImode)));
191090075Sobrien	emit_insn (gen_iorsi3 (subtarget, op1,
1911169689Skan			       gen_int_mode (op3_value << start_bit, SImode)));
191290075Sobrien      }
191390075Sobrien    else if (start_bit == 0
191490075Sobrien	     && !(const_ok_for_arm (mask)
191590075Sobrien		  || const_ok_for_arm (~mask)))
191690075Sobrien      {
191790075Sobrien	/* A Trick, since we are setting the bottom bits in the word,
191890075Sobrien	   we can shift operand[3] up, operand[0] down, OR them together
191990075Sobrien	   and rotate the result back again.  This takes 3 insns, and
1920132718Skan	   the third might be mergeable into another op.  */
192190075Sobrien	/* The shift up copes with the possibility that operand[3] is
192290075Sobrien           wider than the bitfield.  */
192390075Sobrien	rtx op0 = gen_reg_rtx (SImode);
192490075Sobrien	rtx op1 = gen_reg_rtx (SImode);
192590075Sobrien
192690075Sobrien	emit_insn (gen_ashlsi3 (op0, operands[3], GEN_INT (32 - width)));
192790075Sobrien	emit_insn (gen_lshrsi3 (op1, operands[0], operands[1]));
192890075Sobrien	emit_insn (gen_iorsi3  (op1, op1, op0));
192990075Sobrien	emit_insn (gen_rotlsi3 (subtarget, op1, operands[1]));
193090075Sobrien      }
193190075Sobrien    else if ((width + start_bit == 32)
193290075Sobrien	     && !(const_ok_for_arm (mask)
193390075Sobrien		  || const_ok_for_arm (~mask)))
193490075Sobrien      {
193590075Sobrien	/* Similar trick, but slightly less efficient.  */
193690075Sobrien
193790075Sobrien	rtx op0 = gen_reg_rtx (SImode);
193890075Sobrien	rtx op1 = gen_reg_rtx (SImode);
193990075Sobrien
194090075Sobrien	emit_insn (gen_ashlsi3 (op0, operands[3], GEN_INT (32 - width)));
194190075Sobrien	emit_insn (gen_ashlsi3 (op1, operands[0], operands[1]));
194290075Sobrien	emit_insn (gen_lshrsi3 (op1, op1, operands[1]));
194390075Sobrien	emit_insn (gen_iorsi3 (subtarget, op1, op0));
194490075Sobrien      }
194590075Sobrien    else
194690075Sobrien      {
1947169689Skan	rtx op0 = gen_int_mode (mask, SImode);
194890075Sobrien	rtx op1 = gen_reg_rtx (SImode);
194990075Sobrien	rtx op2 = gen_reg_rtx (SImode);
195090075Sobrien
195190075Sobrien	if (!(const_ok_for_arm (mask) || const_ok_for_arm (~mask)))
195290075Sobrien	  {
195390075Sobrien	    rtx tmp = gen_reg_rtx (SImode);
195490075Sobrien
195590075Sobrien	    emit_insn (gen_movsi (tmp, op0));
195690075Sobrien	    op0 = tmp;
195790075Sobrien	  }
195890075Sobrien
195990075Sobrien	/* Mask out any bits in operand[3] that are not needed.  */
196090075Sobrien	   emit_insn (gen_andsi3 (op1, operands[3], op0));
196190075Sobrien
196290075Sobrien	if (GET_CODE (op0) == CONST_INT
196390075Sobrien	    && (const_ok_for_arm (mask << start_bit)
196490075Sobrien		|| const_ok_for_arm (~(mask << start_bit))))
196590075Sobrien	  {
1966169689Skan	    op0 = gen_int_mode (~(mask << start_bit), SImode);
196790075Sobrien	    emit_insn (gen_andsi3 (op2, operands[0], op0));
196890075Sobrien	  }
196990075Sobrien	else
197090075Sobrien	  {
197190075Sobrien	    if (GET_CODE (op0) == CONST_INT)
197290075Sobrien	      {
197390075Sobrien		rtx tmp = gen_reg_rtx (SImode);
197490075Sobrien
197590075Sobrien		emit_insn (gen_movsi (tmp, op0));
197690075Sobrien		op0 = tmp;
197790075Sobrien	      }
197890075Sobrien
197990075Sobrien	    if (start_bit != 0)
198090075Sobrien	      emit_insn (gen_ashlsi3 (op0, op0, operands[2]));
198190075Sobrien	    
198290075Sobrien	    emit_insn (gen_andsi_notsi_si (op2, operands[0], op0));
198390075Sobrien	  }
198490075Sobrien
198590075Sobrien	if (start_bit != 0)
198690075Sobrien          emit_insn (gen_ashlsi3 (op1, op1, operands[2]));
198790075Sobrien
198890075Sobrien	emit_insn (gen_iorsi3 (subtarget, op1, op2));
198990075Sobrien      }
199090075Sobrien
199190075Sobrien    if (subtarget != target)
199290075Sobrien      {
199390075Sobrien	/* If TARGET is still a SUBREG, then it must be wider than a word,
199490075Sobrien	   so we must be careful only to set the subword we were asked to.  */
199590075Sobrien	if (GET_CODE (target) == SUBREG)
199690075Sobrien	  emit_move_insn (target, subtarget);
199790075Sobrien	else
199890075Sobrien	  emit_move_insn (target, gen_lowpart (GET_MODE (target), subtarget));
199990075Sobrien      }
200090075Sobrien
200190075Sobrien    DONE;
200290075Sobrien  }"
200390075Sobrien)
200490075Sobrien
200590075Sobrien; constants for op 2 will never be given to these patterns.
200690075Sobrien(define_insn_and_split "*anddi_notdi_di"
200790075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
200890075Sobrien	(and:DI (not:DI (match_operand:DI 1 "s_register_operand" "r,0"))
200990075Sobrien		(match_operand:DI 2 "s_register_operand" "0,r")))]
201090075Sobrien  "TARGET_ARM"
201190075Sobrien  "#"
2012132718Skan  "TARGET_ARM && reload_completed && ! IS_IWMMXT_REGNUM (REGNO (operands[0]))"
201390075Sobrien  [(set (match_dup 0) (and:SI (not:SI (match_dup 1)) (match_dup 2)))
201490075Sobrien   (set (match_dup 3) (and:SI (not:SI (match_dup 4)) (match_dup 5)))]
201590075Sobrien  "
201690075Sobrien  {
201790075Sobrien    operands[3] = gen_highpart (SImode, operands[0]);
201890075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
201990075Sobrien    operands[4] = gen_highpart (SImode, operands[1]);
202090075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
202190075Sobrien    operands[5] = gen_highpart (SImode, operands[2]);
202290075Sobrien    operands[2] = gen_lowpart (SImode, operands[2]);
202390075Sobrien  }"
202490075Sobrien  [(set_attr "length" "8")
202590075Sobrien   (set_attr "predicable" "yes")]
202690075Sobrien)
202790075Sobrien  
202890075Sobrien(define_insn_and_split "*anddi_notzesidi_di"
202990075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
203090075Sobrien	(and:DI (not:DI (zero_extend:DI
203190075Sobrien			 (match_operand:SI 2 "s_register_operand" "r,r")))
203290075Sobrien		(match_operand:DI 1 "s_register_operand" "0,?r")))]
203390075Sobrien  "TARGET_ARM"
203490075Sobrien  "@
203590075Sobrien   bic%?\\t%Q0, %Q1, %2
203690075Sobrien   #"
203790075Sobrien  ; (not (zero_extend ...)) allows us to just copy the high word from
203890075Sobrien  ; operand1 to operand0.
203990075Sobrien  "TARGET_ARM
204090075Sobrien   && reload_completed
204190075Sobrien   && operands[0] != operands[1]"
2042117395Skan  [(set (match_dup 0) (and:SI (not:SI (match_dup 2)) (match_dup 1)))
204390075Sobrien   (set (match_dup 3) (match_dup 4))]
204490075Sobrien  "
204590075Sobrien  {
204690075Sobrien    operands[3] = gen_highpart (SImode, operands[0]);
204790075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
204890075Sobrien    operands[4] = gen_highpart (SImode, operands[1]);
204990075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
205090075Sobrien  }"
205190075Sobrien  [(set_attr "length" "4,8")
205290075Sobrien   (set_attr "predicable" "yes")]
205390075Sobrien)
205490075Sobrien  
205590075Sobrien(define_insn_and_split "*anddi_notsesidi_di"
205690075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
205790075Sobrien	(and:DI (not:DI (sign_extend:DI
205890075Sobrien			 (match_operand:SI 2 "s_register_operand" "r,r")))
2059117395Skan		(match_operand:DI 1 "s_register_operand" "0,r")))]
206090075Sobrien  "TARGET_ARM"
206190075Sobrien  "#"
206290075Sobrien  "TARGET_ARM && reload_completed"
2063117395Skan  [(set (match_dup 0) (and:SI (not:SI (match_dup 2)) (match_dup 1)))
206490075Sobrien   (set (match_dup 3) (and:SI (not:SI
206590075Sobrien				(ashiftrt:SI (match_dup 2) (const_int 31)))
206690075Sobrien			       (match_dup 4)))]
206790075Sobrien  "
206890075Sobrien  {
206990075Sobrien    operands[3] = gen_highpart (SImode, operands[0]);
207090075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
207190075Sobrien    operands[4] = gen_highpart (SImode, operands[1]);
207290075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
207390075Sobrien  }"
207490075Sobrien  [(set_attr "length" "8")
207590075Sobrien   (set_attr "predicable" "yes")]
207690075Sobrien)
207790075Sobrien  
207890075Sobrien(define_insn "andsi_notsi_si"
207990075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
208090075Sobrien	(and:SI (not:SI (match_operand:SI 2 "s_register_operand" "r"))
208190075Sobrien		(match_operand:SI 1 "s_register_operand" "r")))]
208290075Sobrien  "TARGET_ARM"
208390075Sobrien  "bic%?\\t%0, %1, %2"
208490075Sobrien  [(set_attr "predicable" "yes")]
208590075Sobrien)
208690075Sobrien
208790075Sobrien(define_insn "bicsi3"
208890075Sobrien  [(set (match_operand:SI                 0 "register_operand" "=l")
208990075Sobrien	(and:SI (not:SI (match_operand:SI 1 "register_operand" "l"))
209090075Sobrien		(match_operand:SI         2 "register_operand" "0")))]
209190075Sobrien  "TARGET_THUMB"
209290075Sobrien  "bic\\t%0, %0, %1"
209390075Sobrien  [(set_attr "length" "2")]
209490075Sobrien)
209590075Sobrien
209690075Sobrien(define_insn "andsi_not_shiftsi_si"
2097169689Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
2098169689Skan	(and:SI (not:SI (match_operator:SI 4 "shift_operator"
2099169689Skan			 [(match_operand:SI 2 "s_register_operand" "r")
2100169689Skan			  (match_operand:SI 3 "arm_rhs_operand" "rM")]))
2101169689Skan		(match_operand:SI 1 "s_register_operand" "r")))]
210290075Sobrien  "TARGET_ARM"
210390075Sobrien  "bic%?\\t%0, %1, %2%S4"
210490075Sobrien  [(set_attr "predicable" "yes")
210590075Sobrien   (set_attr "shift" "2")
2106169689Skan   (set (attr "type") (if_then_else (match_operand 3 "const_int_operand" "")
2107169689Skan		      (const_string "alu_shift")
2108169689Skan		      (const_string "alu_shift_reg")))]
210990075Sobrien)
211090075Sobrien
211190075Sobrien(define_insn "*andsi_notsi_si_compare0"
211290075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
211390075Sobrien	(compare:CC_NOOV
211490075Sobrien	 (and:SI (not:SI (match_operand:SI 2 "s_register_operand" "r"))
211590075Sobrien		 (match_operand:SI 1 "s_register_operand" "r"))
211690075Sobrien	 (const_int 0)))
211790075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
211890075Sobrien	(and:SI (not:SI (match_dup 2)) (match_dup 1)))]
211990075Sobrien  "TARGET_ARM"
212090075Sobrien  "bic%?s\\t%0, %1, %2"
212190075Sobrien  [(set_attr "conds" "set")]
212290075Sobrien)
212390075Sobrien
212490075Sobrien(define_insn "*andsi_notsi_si_compare0_scratch"
212590075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
212690075Sobrien	(compare:CC_NOOV
212790075Sobrien	 (and:SI (not:SI (match_operand:SI 2 "s_register_operand" "r"))
212890075Sobrien		 (match_operand:SI 1 "s_register_operand" "r"))
212990075Sobrien	 (const_int 0)))
213090075Sobrien   (clobber (match_scratch:SI 0 "=r"))]
213190075Sobrien  "TARGET_ARM"
213290075Sobrien  "bic%?s\\t%0, %1, %2"
213390075Sobrien  [(set_attr "conds" "set")]
213490075Sobrien)
213590075Sobrien
213690075Sobrien(define_insn "iordi3"
213790075Sobrien  [(set (match_operand:DI         0 "s_register_operand" "=&r,&r")
213890075Sobrien	(ior:DI (match_operand:DI 1 "s_register_operand"  "%0,r")
213990075Sobrien		(match_operand:DI 2 "s_register_operand"   "r,r")))]
2140132718Skan  "TARGET_ARM && ! TARGET_IWMMXT"
214190075Sobrien  "#"
214290075Sobrien  [(set_attr "length" "8")
214390075Sobrien   (set_attr "predicable" "yes")]
214490075Sobrien)
214590075Sobrien
214690075Sobrien(define_insn "*iordi_zesidi_di"
214790075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
214890075Sobrien	(ior:DI (zero_extend:DI
214990075Sobrien		 (match_operand:SI 2 "s_register_operand" "r,r"))
215090075Sobrien		(match_operand:DI 1 "s_register_operand" "0,?r")))]
215190075Sobrien  "TARGET_ARM"
215290075Sobrien  "@
215390075Sobrien   orr%?\\t%Q0, %Q1, %2
215490075Sobrien   #"
215590075Sobrien  [(set_attr "length" "4,8")
215690075Sobrien   (set_attr "predicable" "yes")]
215790075Sobrien)
215890075Sobrien
215990075Sobrien(define_insn "*iordi_sesidi_di"
216090075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
216190075Sobrien	(ior:DI (sign_extend:DI
216290075Sobrien		 (match_operand:SI 2 "s_register_operand" "r,r"))
216390075Sobrien		(match_operand:DI 1 "s_register_operand" "?r,0")))]
216490075Sobrien  "TARGET_ARM"
216590075Sobrien  "#"
216690075Sobrien  [(set_attr "length" "8")
216790075Sobrien   (set_attr "predicable" "yes")]
216890075Sobrien)
216990075Sobrien
217090075Sobrien(define_expand "iorsi3"
217190075Sobrien  [(set (match_operand:SI         0 "s_register_operand" "")
217290075Sobrien	(ior:SI (match_operand:SI 1 "s_register_operand" "")
217390075Sobrien		(match_operand:SI 2 "reg_or_int_operand" "")))]
217490075Sobrien  "TARGET_EITHER"
217590075Sobrien  "
217690075Sobrien  if (GET_CODE (operands[2]) == CONST_INT)
217790075Sobrien    {
217890075Sobrien      if (TARGET_ARM)
217990075Sobrien        {
2180169689Skan          arm_split_constant (IOR, SImode, NULL_RTX,
2181169689Skan	                      INTVAL (operands[2]), operands[0], operands[1],
2182169689Skan			      optimize && !no_new_pseudos);
218390075Sobrien          DONE;
218490075Sobrien	}
218590075Sobrien      else /* TARGET_THUMB */
218690075Sobrien	operands [2] = force_reg (SImode, operands [2]);
218790075Sobrien    }
218890075Sobrien  "
218990075Sobrien)
219090075Sobrien
219190075Sobrien(define_insn_and_split "*arm_iorsi3"
219290075Sobrien  [(set (match_operand:SI         0 "s_register_operand" "=r,r")
219390075Sobrien	(ior:SI (match_operand:SI 1 "s_register_operand" "r,r")
219490075Sobrien		(match_operand:SI 2 "reg_or_int_operand" "rI,?n")))]
219590075Sobrien  "TARGET_ARM"
219690075Sobrien  "@
219790075Sobrien   orr%?\\t%0, %1, %2
219890075Sobrien   #"
219990075Sobrien  "TARGET_ARM
220090075Sobrien   && GET_CODE (operands[2]) == CONST_INT
220190075Sobrien   && !const_ok_for_arm (INTVAL (operands[2]))"
220290075Sobrien  [(clobber (const_int 0))]
220390075Sobrien  "
2204169689Skan  arm_split_constant (IOR, SImode, curr_insn, 
2205169689Skan                      INTVAL (operands[2]), operands[0], operands[1], 0);
220690075Sobrien  DONE;
220790075Sobrien  "
220890075Sobrien  [(set_attr "length" "4,16")
220990075Sobrien   (set_attr "predicable" "yes")]
221090075Sobrien)
221190075Sobrien
221290075Sobrien(define_insn "*thumb_iorsi3"
221390075Sobrien  [(set (match_operand:SI         0 "register_operand" "=l")
221490075Sobrien	(ior:SI (match_operand:SI 1 "register_operand" "%0")
221590075Sobrien		(match_operand:SI 2 "register_operand" "l")))]
221690075Sobrien  "TARGET_THUMB"
221790075Sobrien  "orr\\t%0, %0, %2"
221890075Sobrien  [(set_attr "length" "2")]
221990075Sobrien)
222090075Sobrien
222190075Sobrien(define_peephole2
222290075Sobrien  [(match_scratch:SI 3 "r")
2223169689Skan   (set (match_operand:SI 0 "arm_general_register_operand" "")
2224169689Skan	(ior:SI (match_operand:SI 1 "arm_general_register_operand" "")
222590075Sobrien		(match_operand:SI 2 "const_int_operand" "")))]
222690075Sobrien  "TARGET_ARM
222790075Sobrien   && !const_ok_for_arm (INTVAL (operands[2]))
222890075Sobrien   && const_ok_for_arm (~INTVAL (operands[2]))"
222990075Sobrien  [(set (match_dup 3) (match_dup 2))
223090075Sobrien   (set (match_dup 0) (ior:SI (match_dup 1) (match_dup 3)))]
223190075Sobrien  ""
223290075Sobrien)
223390075Sobrien
223490075Sobrien(define_insn "*iorsi3_compare0"
223590075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
223690075Sobrien	(compare:CC_NOOV (ior:SI (match_operand:SI 1 "s_register_operand" "%r")
223790075Sobrien				 (match_operand:SI 2 "arm_rhs_operand" "rI"))
223890075Sobrien			 (const_int 0)))
223990075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
224090075Sobrien	(ior:SI (match_dup 1) (match_dup 2)))]
224190075Sobrien  "TARGET_ARM"
224290075Sobrien  "orr%?s\\t%0, %1, %2"
224390075Sobrien  [(set_attr "conds" "set")]
224490075Sobrien)
224590075Sobrien
224690075Sobrien(define_insn "*iorsi3_compare0_scratch"
224790075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
224890075Sobrien	(compare:CC_NOOV (ior:SI (match_operand:SI 1 "s_register_operand" "%r")
224990075Sobrien				 (match_operand:SI 2 "arm_rhs_operand" "rI"))
225090075Sobrien			 (const_int 0)))
225190075Sobrien   (clobber (match_scratch:SI 0 "=r"))]
225290075Sobrien  "TARGET_ARM"
225390075Sobrien  "orr%?s\\t%0, %1, %2"
225490075Sobrien  [(set_attr "conds" "set")]
225590075Sobrien)
225690075Sobrien
225790075Sobrien(define_insn "xordi3"
225890075Sobrien  [(set (match_operand:DI         0 "s_register_operand" "=&r,&r")
225990075Sobrien	(xor:DI (match_operand:DI 1 "s_register_operand"  "%0,r")
226090075Sobrien		(match_operand:DI 2 "s_register_operand"   "r,r")))]
2261132718Skan  "TARGET_ARM && !TARGET_IWMMXT"
226290075Sobrien  "#"
226390075Sobrien  [(set_attr "length" "8")
226490075Sobrien   (set_attr "predicable" "yes")]
226590075Sobrien)
226690075Sobrien
226790075Sobrien(define_insn "*xordi_zesidi_di"
226890075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
226990075Sobrien	(xor:DI (zero_extend:DI
227090075Sobrien		 (match_operand:SI 2 "s_register_operand" "r,r"))
227190075Sobrien		(match_operand:DI 1 "s_register_operand" "0,?r")))]
227290075Sobrien  "TARGET_ARM"
227390075Sobrien  "@
227490075Sobrien   eor%?\\t%Q0, %Q1, %2
227590075Sobrien   #"
227690075Sobrien  [(set_attr "length" "4,8")
227790075Sobrien   (set_attr "predicable" "yes")]
227890075Sobrien)
227990075Sobrien
228090075Sobrien(define_insn "*xordi_sesidi_di"
228190075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
228290075Sobrien	(xor:DI (sign_extend:DI
228390075Sobrien		 (match_operand:SI 2 "s_register_operand" "r,r"))
228490075Sobrien		(match_operand:DI 1 "s_register_operand" "?r,0")))]
228590075Sobrien  "TARGET_ARM"
228690075Sobrien  "#"
228790075Sobrien  [(set_attr "length" "8")
228890075Sobrien   (set_attr "predicable" "yes")]
228990075Sobrien)
229090075Sobrien
229190075Sobrien(define_expand "xorsi3"
229290075Sobrien  [(set (match_operand:SI         0 "s_register_operand" "")
229390075Sobrien	(xor:SI (match_operand:SI 1 "s_register_operand" "")
229490075Sobrien		(match_operand:SI 2 "arm_rhs_operand"  "")))]
229590075Sobrien  "TARGET_EITHER"
229690075Sobrien  "if (TARGET_THUMB)
229790075Sobrien     if (GET_CODE (operands[2]) == CONST_INT)
229890075Sobrien       operands[2] = force_reg (SImode, operands[2]);
229990075Sobrien  "
230090075Sobrien)
230190075Sobrien
230290075Sobrien(define_insn "*arm_xorsi3"
230390075Sobrien  [(set (match_operand:SI         0 "s_register_operand" "=r")
230490075Sobrien	(xor:SI (match_operand:SI 1 "s_register_operand" "r")
230590075Sobrien		(match_operand:SI 2 "arm_rhs_operand" "rI")))]
230690075Sobrien  "TARGET_ARM"
230790075Sobrien  "eor%?\\t%0, %1, %2"
230890075Sobrien  [(set_attr "predicable" "yes")]
230990075Sobrien)
231090075Sobrien
231190075Sobrien(define_insn "*thumb_xorsi3"
231290075Sobrien  [(set (match_operand:SI         0 "register_operand" "=l")
231390075Sobrien	(xor:SI (match_operand:SI 1 "register_operand" "%0")
231490075Sobrien		(match_operand:SI 2 "register_operand" "l")))]
231590075Sobrien  "TARGET_THUMB"
231690075Sobrien  "eor\\t%0, %0, %2"
231790075Sobrien  [(set_attr "length" "2")]
231890075Sobrien)
231990075Sobrien
232090075Sobrien(define_insn "*xorsi3_compare0"
232190075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
232290075Sobrien	(compare:CC_NOOV (xor:SI (match_operand:SI 1 "s_register_operand" "r")
232390075Sobrien				 (match_operand:SI 2 "arm_rhs_operand" "rI"))
232490075Sobrien			 (const_int 0)))
232590075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
232690075Sobrien	(xor:SI (match_dup 1) (match_dup 2)))]
232790075Sobrien  "TARGET_ARM"
232890075Sobrien  "eor%?s\\t%0, %1, %2"
232990075Sobrien  [(set_attr "conds" "set")]
233090075Sobrien)
233190075Sobrien
233290075Sobrien(define_insn "*xorsi3_compare0_scratch"
233390075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
233490075Sobrien	(compare:CC_NOOV (xor:SI (match_operand:SI 0 "s_register_operand" "r")
233590075Sobrien				 (match_operand:SI 1 "arm_rhs_operand" "rI"))
233690075Sobrien			 (const_int 0)))]
233790075Sobrien  "TARGET_ARM"
233890075Sobrien  "teq%?\\t%0, %1"
233990075Sobrien  [(set_attr "conds" "set")]
234090075Sobrien)
234190075Sobrien
234290075Sobrien; By splitting (IOR (AND (NOT A) (NOT B)) C) as D = AND (IOR A B) (NOT C), 
234390075Sobrien; (NOT D) we can sometimes merge the final NOT into one of the following
234490075Sobrien; insns.
234590075Sobrien
234690075Sobrien(define_split
2347117395Skan  [(set (match_operand:SI 0 "s_register_operand" "")
2348117395Skan	(ior:SI (and:SI (not:SI (match_operand:SI 1 "s_register_operand" ""))
2349117395Skan			(not:SI (match_operand:SI 2 "arm_rhs_operand" "")))
2350117395Skan		(match_operand:SI 3 "arm_rhs_operand" "")))
2351117395Skan   (clobber (match_operand:SI 4 "s_register_operand" ""))]
235290075Sobrien  "TARGET_ARM"
235390075Sobrien  [(set (match_dup 4) (and:SI (ior:SI (match_dup 1) (match_dup 2))
235490075Sobrien			      (not:SI (match_dup 3))))
235590075Sobrien   (set (match_dup 0) (not:SI (match_dup 4)))]
235690075Sobrien  ""
235790075Sobrien)
235890075Sobrien
235990075Sobrien(define_insn "*andsi_iorsi3_notsi"
236090075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r")
236190075Sobrien	(and:SI (ior:SI (match_operand:SI 1 "s_register_operand" "r,r,0")
236290075Sobrien			(match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))
236390075Sobrien		(not:SI (match_operand:SI 3 "arm_rhs_operand" "rI,rI,rI"))))]
236490075Sobrien  "TARGET_ARM"
236590075Sobrien  "orr%?\\t%0, %1, %2\;bic%?\\t%0, %0, %3"
236690075Sobrien  [(set_attr "length" "8")
236790075Sobrien   (set_attr "predicable" "yes")]
236890075Sobrien)
236990075Sobrien
2370132718Skan(define_split
2371132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
2372132718Skan	(match_operator:SI 1 "logical_binary_operator"
2373132718Skan	 [(zero_extract:SI (match_operand:SI 2 "s_register_operand" "")
2374132718Skan			   (match_operand:SI 3 "const_int_operand" "")
2375132718Skan			   (match_operand:SI 4 "const_int_operand" ""))
2376132718Skan	  (match_operator:SI 9 "logical_binary_operator"
2377132718Skan	   [(lshiftrt:SI (match_operand:SI 5 "s_register_operand" "")
2378132718Skan			 (match_operand:SI 6 "const_int_operand" ""))
2379132718Skan	    (match_operand:SI 7 "s_register_operand" "")])]))
2380132718Skan   (clobber (match_operand:SI 8 "s_register_operand" ""))]
2381132718Skan  "TARGET_ARM
2382132718Skan   && GET_CODE (operands[1]) == GET_CODE (operands[9])
2383132718Skan   && INTVAL (operands[3]) == 32 - INTVAL (operands[6])"
2384132718Skan  [(set (match_dup 8)
2385132718Skan	(match_op_dup 1
2386132718Skan	 [(ashift:SI (match_dup 2) (match_dup 4))
2387132718Skan	  (match_dup 5)]))
2388132718Skan   (set (match_dup 0)
2389132718Skan	(match_op_dup 1
2390132718Skan	 [(lshiftrt:SI (match_dup 8) (match_dup 6))
2391132718Skan	  (match_dup 7)]))]
2392132718Skan  "
2393132718Skan  operands[4] = GEN_INT (32 - (INTVAL (operands[3]) + INTVAL (operands[4])));
2394132718Skan")
2395132718Skan
2396132718Skan(define_split
2397132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
2398132718Skan	(match_operator:SI 1 "logical_binary_operator"
2399132718Skan	 [(match_operator:SI 9 "logical_binary_operator"
2400132718Skan	   [(lshiftrt:SI (match_operand:SI 5 "s_register_operand" "")
2401132718Skan			 (match_operand:SI 6 "const_int_operand" ""))
2402132718Skan	    (match_operand:SI 7 "s_register_operand" "")])
2403132718Skan	  (zero_extract:SI (match_operand:SI 2 "s_register_operand" "")
2404132718Skan			   (match_operand:SI 3 "const_int_operand" "")
2405132718Skan			   (match_operand:SI 4 "const_int_operand" ""))]))
2406132718Skan   (clobber (match_operand:SI 8 "s_register_operand" ""))]
2407132718Skan  "TARGET_ARM
2408132718Skan   && GET_CODE (operands[1]) == GET_CODE (operands[9])
2409132718Skan   && INTVAL (operands[3]) == 32 - INTVAL (operands[6])"
2410132718Skan  [(set (match_dup 8)
2411132718Skan	(match_op_dup 1
2412132718Skan	 [(ashift:SI (match_dup 2) (match_dup 4))
2413132718Skan	  (match_dup 5)]))
2414132718Skan   (set (match_dup 0)
2415132718Skan	(match_op_dup 1
2416132718Skan	 [(lshiftrt:SI (match_dup 8) (match_dup 6))
2417132718Skan	  (match_dup 7)]))]
2418132718Skan  "
2419132718Skan  operands[4] = GEN_INT (32 - (INTVAL (operands[3]) + INTVAL (operands[4])));
2420132718Skan")
2421132718Skan
2422132718Skan(define_split
2423132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
2424132718Skan	(match_operator:SI 1 "logical_binary_operator"
2425132718Skan	 [(sign_extract:SI (match_operand:SI 2 "s_register_operand" "")
2426132718Skan			   (match_operand:SI 3 "const_int_operand" "")
2427132718Skan			   (match_operand:SI 4 "const_int_operand" ""))
2428132718Skan	  (match_operator:SI 9 "logical_binary_operator"
2429132718Skan	   [(ashiftrt:SI (match_operand:SI 5 "s_register_operand" "")
2430132718Skan			 (match_operand:SI 6 "const_int_operand" ""))
2431132718Skan	    (match_operand:SI 7 "s_register_operand" "")])]))
2432132718Skan   (clobber (match_operand:SI 8 "s_register_operand" ""))]
2433132718Skan  "TARGET_ARM
2434132718Skan   && GET_CODE (operands[1]) == GET_CODE (operands[9])
2435132718Skan   && INTVAL (operands[3]) == 32 - INTVAL (operands[6])"
2436132718Skan  [(set (match_dup 8)
2437132718Skan	(match_op_dup 1
2438132718Skan	 [(ashift:SI (match_dup 2) (match_dup 4))
2439132718Skan	  (match_dup 5)]))
2440132718Skan   (set (match_dup 0)
2441132718Skan	(match_op_dup 1
2442132718Skan	 [(ashiftrt:SI (match_dup 8) (match_dup 6))
2443132718Skan	  (match_dup 7)]))]
2444132718Skan  "
2445132718Skan  operands[4] = GEN_INT (32 - (INTVAL (operands[3]) + INTVAL (operands[4])));
2446132718Skan")
2447132718Skan
2448132718Skan(define_split
2449132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
2450132718Skan	(match_operator:SI 1 "logical_binary_operator"
2451132718Skan	 [(match_operator:SI 9 "logical_binary_operator"
2452132718Skan	   [(ashiftrt:SI (match_operand:SI 5 "s_register_operand" "")
2453132718Skan			 (match_operand:SI 6 "const_int_operand" ""))
2454132718Skan	    (match_operand:SI 7 "s_register_operand" "")])
2455132718Skan	  (sign_extract:SI (match_operand:SI 2 "s_register_operand" "")
2456132718Skan			   (match_operand:SI 3 "const_int_operand" "")
2457132718Skan			   (match_operand:SI 4 "const_int_operand" ""))]))
2458132718Skan   (clobber (match_operand:SI 8 "s_register_operand" ""))]
2459132718Skan  "TARGET_ARM
2460132718Skan   && GET_CODE (operands[1]) == GET_CODE (operands[9])
2461132718Skan   && INTVAL (operands[3]) == 32 - INTVAL (operands[6])"
2462132718Skan  [(set (match_dup 8)
2463132718Skan	(match_op_dup 1
2464132718Skan	 [(ashift:SI (match_dup 2) (match_dup 4))
2465132718Skan	  (match_dup 5)]))
2466132718Skan   (set (match_dup 0)
2467132718Skan	(match_op_dup 1
2468132718Skan	 [(ashiftrt:SI (match_dup 8) (match_dup 6))
2469132718Skan	  (match_dup 7)]))]
2470132718Skan  "
2471132718Skan  operands[4] = GEN_INT (32 - (INTVAL (operands[3]) + INTVAL (operands[4])));
2472132718Skan")
247390075Sobrien
247490075Sobrien
247590075Sobrien;; Minimum and maximum insns
247690075Sobrien
2477169689Skan(define_expand "smaxsi3"
2478169689Skan  [(parallel [
2479169689Skan    (set (match_operand:SI 0 "s_register_operand" "")
2480169689Skan	 (smax:SI (match_operand:SI 1 "s_register_operand" "")
2481169689Skan		  (match_operand:SI 2 "arm_rhs_operand" "")))
2482169689Skan    (clobber (reg:CC CC_REGNUM))])]
2483169689Skan  "TARGET_ARM"
2484169689Skan  "
2485169689Skan  if (operands[2] == const0_rtx || operands[2] == constm1_rtx)
2486169689Skan    {
2487169689Skan      /* No need for a clobber of the condition code register here.  */
2488169689Skan      emit_insn (gen_rtx_SET (VOIDmode, operands[0],
2489169689Skan			      gen_rtx_SMAX (SImode, operands[1],
2490169689Skan					    operands[2])));
2491169689Skan      DONE;
2492169689Skan    }
2493169689Skan")
2494169689Skan
2495169689Skan(define_insn "*smax_0"
2496169689Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
2497169689Skan	(smax:SI (match_operand:SI 1 "s_register_operand" "r")
2498169689Skan		 (const_int 0)))]
2499169689Skan  "TARGET_ARM"
2500169689Skan  "bic%?\\t%0, %1, %1, asr #31"
2501169689Skan  [(set_attr "predicable" "yes")]
2502169689Skan)
2503169689Skan
2504169689Skan(define_insn "*smax_m1"
2505169689Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
2506169689Skan	(smax:SI (match_operand:SI 1 "s_register_operand" "r")
2507169689Skan		 (const_int -1)))]
2508169689Skan  "TARGET_ARM"
2509169689Skan  "orr%?\\t%0, %1, %1, asr #31"
2510169689Skan  [(set_attr "predicable" "yes")]
2511169689Skan)
2512169689Skan
2513169689Skan(define_insn "*smax_insn"
2514169689Skan  [(set (match_operand:SI          0 "s_register_operand" "=r,r")
2515169689Skan	(smax:SI (match_operand:SI 1 "s_register_operand"  "%0,?r")
2516169689Skan		 (match_operand:SI 2 "arm_rhs_operand"    "rI,rI")))
251790075Sobrien   (clobber (reg:CC CC_REGNUM))]
251890075Sobrien  "TARGET_ARM"
251990075Sobrien  "@
252090075Sobrien   cmp\\t%1, %2\;movlt\\t%0, %2
252190075Sobrien   cmp\\t%1, %2\;movge\\t%0, %1\;movlt\\t%0, %2"
252290075Sobrien  [(set_attr "conds" "clob")
2523169689Skan   (set_attr "length" "8,12")]
252490075Sobrien)
252590075Sobrien
2526169689Skan(define_expand "sminsi3"
2527169689Skan  [(parallel [
2528169689Skan    (set (match_operand:SI 0 "s_register_operand" "")
2529169689Skan	 (smin:SI (match_operand:SI 1 "s_register_operand" "")
2530169689Skan		  (match_operand:SI 2 "arm_rhs_operand" "")))
2531169689Skan    (clobber (reg:CC CC_REGNUM))])]
2532169689Skan  "TARGET_ARM"
2533169689Skan  "
2534169689Skan  if (operands[2] == const0_rtx)
2535169689Skan    {
2536169689Skan      /* No need for a clobber of the condition code register here.  */
2537169689Skan      emit_insn (gen_rtx_SET (VOIDmode, operands[0],
2538169689Skan			      gen_rtx_SMIN (SImode, operands[1],
2539169689Skan					    operands[2])));
2540169689Skan      DONE;
2541169689Skan    }
2542169689Skan")
2543169689Skan
2544169689Skan(define_insn "*smin_0"
2545169689Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
2546169689Skan	(smin:SI (match_operand:SI 1 "s_register_operand" "r")
2547169689Skan		 (const_int 0)))]
2548169689Skan  "TARGET_ARM"
2549169689Skan  "and%?\\t%0, %1, %1, asr #31"
2550169689Skan  [(set_attr "predicable" "yes")]
2551169689Skan)
2552169689Skan
2553169689Skan(define_insn "*smin_insn"
2554169689Skan  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
2555169689Skan	(smin:SI (match_operand:SI 1 "s_register_operand" "%0,?r")
2556169689Skan		 (match_operand:SI 2 "arm_rhs_operand" "rI,rI")))
255790075Sobrien   (clobber (reg:CC CC_REGNUM))]
255890075Sobrien  "TARGET_ARM"
255990075Sobrien  "@
256090075Sobrien   cmp\\t%1, %2\;movge\\t%0, %2
256190075Sobrien   cmp\\t%1, %2\;movlt\\t%0, %1\;movge\\t%0, %2"
256290075Sobrien  [(set_attr "conds" "clob")
2563169689Skan   (set_attr "length" "8,12")]
256490075Sobrien)
256590075Sobrien
256690075Sobrien(define_insn "umaxsi3"
256790075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
256890075Sobrien	(umax:SI (match_operand:SI 1 "s_register_operand" "0,r,?r")
256990075Sobrien		 (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")))
257090075Sobrien   (clobber (reg:CC CC_REGNUM))]
257190075Sobrien  "TARGET_ARM"
257290075Sobrien  "@
257390075Sobrien   cmp\\t%1, %2\;movcc\\t%0, %2
257490075Sobrien   cmp\\t%1, %2\;movcs\\t%0, %1
257590075Sobrien   cmp\\t%1, %2\;movcs\\t%0, %1\;movcc\\t%0, %2"
257690075Sobrien  [(set_attr "conds" "clob")
257790075Sobrien   (set_attr "length" "8,8,12")]
257890075Sobrien)
257990075Sobrien
258090075Sobrien(define_insn "uminsi3"
258190075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
258290075Sobrien	(umin:SI (match_operand:SI 1 "s_register_operand" "0,r,?r")
258390075Sobrien		 (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")))
258490075Sobrien   (clobber (reg:CC CC_REGNUM))]
258590075Sobrien  "TARGET_ARM"
258690075Sobrien  "@
258790075Sobrien   cmp\\t%1, %2\;movcs\\t%0, %2
258890075Sobrien   cmp\\t%1, %2\;movcc\\t%0, %1
258990075Sobrien   cmp\\t%1, %2\;movcc\\t%0, %1\;movcs\\t%0, %2"
259090075Sobrien  [(set_attr "conds" "clob")
259190075Sobrien   (set_attr "length" "8,8,12")]
259290075Sobrien)
259390075Sobrien
259490075Sobrien(define_insn "*store_minmaxsi"
259590075Sobrien  [(set (match_operand:SI 0 "memory_operand" "=m")
259690075Sobrien	(match_operator:SI 3 "minmax_operator"
259790075Sobrien	 [(match_operand:SI 1 "s_register_operand" "r")
259890075Sobrien	  (match_operand:SI 2 "s_register_operand" "r")]))
259990075Sobrien   (clobber (reg:CC CC_REGNUM))]
260090075Sobrien  "TARGET_ARM"
260190075Sobrien  "*
2602169689Skan  operands[3] = gen_rtx_fmt_ee (minmax_code (operands[3]), SImode,
2603169689Skan				operands[1], operands[2]);
260490075Sobrien  output_asm_insn (\"cmp\\t%1, %2\", operands);
260590075Sobrien  output_asm_insn (\"str%d3\\t%1, %0\", operands);
260690075Sobrien  output_asm_insn (\"str%D3\\t%2, %0\", operands);
260790075Sobrien  return \"\";
260890075Sobrien  "
260990075Sobrien  [(set_attr "conds" "clob")
261090075Sobrien   (set_attr "length" "12")
261190075Sobrien   (set_attr "type" "store1")]
261290075Sobrien)
261390075Sobrien
261490075Sobrien; Reject the frame pointer in operand[1], since reloading this after
261590075Sobrien; it has been eliminated can cause carnage.
261690075Sobrien(define_insn "*minmax_arithsi"
261790075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
261890075Sobrien	(match_operator:SI 4 "shiftable_operator"
261990075Sobrien	 [(match_operator:SI 5 "minmax_operator"
262090075Sobrien	   [(match_operand:SI 2 "s_register_operand" "r,r")
262190075Sobrien	    (match_operand:SI 3 "arm_rhs_operand" "rI,rI")])
262290075Sobrien	  (match_operand:SI 1 "s_register_operand" "0,?r")]))
262390075Sobrien   (clobber (reg:CC CC_REGNUM))]
2624169689Skan  "TARGET_ARM && !arm_eliminable_register (operands[1])"
262590075Sobrien  "*
262690075Sobrien  {
262790075Sobrien    enum rtx_code code = GET_CODE (operands[4]);
262890075Sobrien
2629169689Skan    operands[5] = gen_rtx_fmt_ee (minmax_code (operands[5]), SImode,
2630169689Skan				  operands[2], operands[3]);
263190075Sobrien    output_asm_insn (\"cmp\\t%2, %3\", operands);
263290075Sobrien    output_asm_insn (\"%i4%d5\\t%0, %1, %2\", operands);
263390075Sobrien    if (which_alternative != 0 || operands[3] != const0_rtx
263490075Sobrien        || (code != PLUS && code != MINUS && code != IOR && code != XOR))
263590075Sobrien      output_asm_insn (\"%i4%D5\\t%0, %1, %3\", operands);
263690075Sobrien    return \"\";
263790075Sobrien  }"
263890075Sobrien  [(set_attr "conds" "clob")
263990075Sobrien   (set_attr "length" "12")]
264090075Sobrien)
264190075Sobrien
264290075Sobrien
264390075Sobrien;; Shift and rotation insns
264490075Sobrien
2645169689Skan(define_expand "ashldi3"
2646169689Skan  [(set (match_operand:DI            0 "s_register_operand" "")
2647169689Skan        (ashift:DI (match_operand:DI 1 "s_register_operand" "")
2648169689Skan                   (match_operand:SI 2 "reg_or_int_operand" "")))]
2649169689Skan  "TARGET_ARM"
2650169689Skan  "
2651169689Skan  if (GET_CODE (operands[2]) == CONST_INT)
2652169689Skan    {
2653169689Skan      if ((HOST_WIDE_INT) INTVAL (operands[2]) == 1)
2654169689Skan        {
2655169689Skan          emit_insn (gen_arm_ashldi3_1bit (operands[0], operands[1]));
2656169689Skan          DONE;
2657169689Skan        }
2658169689Skan        /* Ideally we shouldn't fail here if we could know that operands[1] 
2659169689Skan           ends up already living in an iwmmxt register. Otherwise it's
2660169689Skan           cheaper to have the alternate code being generated than moving
2661169689Skan           values to iwmmxt regs and back.  */
2662169689Skan        FAIL;
2663169689Skan    }
2664169689Skan  else if (!TARGET_REALLY_IWMMXT && !(TARGET_HARD_FLOAT && TARGET_MAVERICK))
2665169689Skan    FAIL;
2666169689Skan  "
2667169689Skan)
2668169689Skan
2669169689Skan(define_insn "arm_ashldi3_1bit"
2670169689Skan  [(set (match_operand:DI            0 "s_register_operand" "=&r,r")
2671169689Skan        (ashift:DI (match_operand:DI 1 "s_register_operand" "?r,0")
2672169689Skan                   (const_int 1)))
2673169689Skan   (clobber (reg:CC CC_REGNUM))]
2674169689Skan  "TARGET_ARM"
2675169689Skan  "movs\\t%Q0, %Q1, asl #1\;adc\\t%R0, %R1, %R1"
2676169689Skan  [(set_attr "conds" "clob")
2677169689Skan   (set_attr "length" "8")]
2678169689Skan)
2679169689Skan
268090075Sobrien(define_expand "ashlsi3"
268190075Sobrien  [(set (match_operand:SI            0 "s_register_operand" "")
268290075Sobrien	(ashift:SI (match_operand:SI 1 "s_register_operand" "")
268390075Sobrien		   (match_operand:SI 2 "arm_rhs_operand" "")))]
268490075Sobrien  "TARGET_EITHER"
268590075Sobrien  "
268690075Sobrien  if (GET_CODE (operands[2]) == CONST_INT
268790075Sobrien      && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31)
268890075Sobrien    {
268990075Sobrien      emit_insn (gen_movsi (operands[0], const0_rtx));
269090075Sobrien      DONE;
269190075Sobrien    }
269290075Sobrien  "
269390075Sobrien)
269490075Sobrien
269590075Sobrien(define_insn "*thumb_ashlsi3"
269690075Sobrien  [(set (match_operand:SI            0 "register_operand" "=l,l")
269790075Sobrien	(ashift:SI (match_operand:SI 1 "register_operand" "l,0")
269890075Sobrien		   (match_operand:SI 2 "nonmemory_operand" "N,l")))]
269990075Sobrien  "TARGET_THUMB"
270090075Sobrien  "lsl\\t%0, %1, %2"
270190075Sobrien  [(set_attr "length" "2")]
270290075Sobrien)
270390075Sobrien
2704169689Skan(define_expand "ashrdi3"
2705169689Skan  [(set (match_operand:DI              0 "s_register_operand" "")
2706169689Skan        (ashiftrt:DI (match_operand:DI 1 "s_register_operand" "")
2707169689Skan                     (match_operand:SI 2 "reg_or_int_operand" "")))]
2708169689Skan  "TARGET_ARM"
2709169689Skan  "
2710169689Skan  if (GET_CODE (operands[2]) == CONST_INT)
2711169689Skan    {
2712169689Skan      if ((HOST_WIDE_INT) INTVAL (operands[2]) == 1)
2713169689Skan        {
2714169689Skan          emit_insn (gen_arm_ashrdi3_1bit (operands[0], operands[1]));
2715169689Skan          DONE;
2716169689Skan        }
2717169689Skan        /* Ideally we shouldn't fail here if we could know that operands[1] 
2718169689Skan           ends up already living in an iwmmxt register. Otherwise it's
2719169689Skan           cheaper to have the alternate code being generated than moving
2720169689Skan           values to iwmmxt regs and back.  */
2721169689Skan        FAIL;
2722169689Skan    }
2723169689Skan  else if (!TARGET_REALLY_IWMMXT)
2724169689Skan    FAIL;
2725169689Skan  "
2726169689Skan)
2727169689Skan
2728169689Skan(define_insn "arm_ashrdi3_1bit"
2729169689Skan  [(set (match_operand:DI              0 "s_register_operand" "=&r,r")
2730169689Skan        (ashiftrt:DI (match_operand:DI 1 "s_register_operand" "?r,0")
2731169689Skan                     (const_int 1)))
2732169689Skan   (clobber (reg:CC CC_REGNUM))]
2733169689Skan  "TARGET_ARM"
2734169689Skan  "movs\\t%R0, %R1, asr #1\;mov\\t%Q0, %Q1, rrx"
2735169689Skan  [(set_attr "conds" "clob")
2736169689Skan   (set_attr "length" "8")]
2737169689Skan)
2738169689Skan
273990075Sobrien(define_expand "ashrsi3"
274090075Sobrien  [(set (match_operand:SI              0 "s_register_operand" "")
274190075Sobrien	(ashiftrt:SI (match_operand:SI 1 "s_register_operand" "")
274290075Sobrien		     (match_operand:SI 2 "arm_rhs_operand" "")))]
274390075Sobrien  "TARGET_EITHER"
274490075Sobrien  "
274590075Sobrien  if (GET_CODE (operands[2]) == CONST_INT
274690075Sobrien      && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31)
274790075Sobrien    operands[2] = GEN_INT (31);
274890075Sobrien  "
274990075Sobrien)
275090075Sobrien
275190075Sobrien(define_insn "*thumb_ashrsi3"
275290075Sobrien  [(set (match_operand:SI              0 "register_operand" "=l,l")
275390075Sobrien	(ashiftrt:SI (match_operand:SI 1 "register_operand" "l,0")
275490075Sobrien		     (match_operand:SI 2 "nonmemory_operand" "N,l")))]
275590075Sobrien  "TARGET_THUMB"
275690075Sobrien  "asr\\t%0, %1, %2"
275790075Sobrien  [(set_attr "length" "2")]
275890075Sobrien)
275990075Sobrien
2760169689Skan(define_expand "lshrdi3"
2761169689Skan  [(set (match_operand:DI              0 "s_register_operand" "")
2762169689Skan        (lshiftrt:DI (match_operand:DI 1 "s_register_operand" "")
2763169689Skan                     (match_operand:SI 2 "reg_or_int_operand" "")))]
2764169689Skan  "TARGET_ARM"
2765169689Skan  "
2766169689Skan  if (GET_CODE (operands[2]) == CONST_INT)
2767169689Skan    {
2768169689Skan      if ((HOST_WIDE_INT) INTVAL (operands[2]) == 1)
2769169689Skan        {
2770169689Skan          emit_insn (gen_arm_lshrdi3_1bit (operands[0], operands[1]));
2771169689Skan          DONE;
2772169689Skan        }
2773169689Skan        /* Ideally we shouldn't fail here if we could know that operands[1] 
2774169689Skan           ends up already living in an iwmmxt register. Otherwise it's
2775169689Skan           cheaper to have the alternate code being generated than moving
2776169689Skan           values to iwmmxt regs and back.  */
2777169689Skan        FAIL;
2778169689Skan    }
2779169689Skan  else if (!TARGET_REALLY_IWMMXT)
2780169689Skan    FAIL;
2781169689Skan  "
2782169689Skan)
2783169689Skan
2784169689Skan(define_insn "arm_lshrdi3_1bit"
2785169689Skan  [(set (match_operand:DI              0 "s_register_operand" "=&r,r")
2786169689Skan        (lshiftrt:DI (match_operand:DI 1 "s_register_operand" "?r,0")
2787169689Skan                     (const_int 1)))
2788169689Skan   (clobber (reg:CC CC_REGNUM))]
2789169689Skan  "TARGET_ARM"
2790169689Skan  "movs\\t%R0, %R1, lsr #1\;mov\\t%Q0, %Q1, rrx"
2791169689Skan  [(set_attr "conds" "clob")
2792169689Skan   (set_attr "length" "8")]
2793169689Skan)
2794169689Skan
279590075Sobrien(define_expand "lshrsi3"
279690075Sobrien  [(set (match_operand:SI              0 "s_register_operand" "")
279790075Sobrien	(lshiftrt:SI (match_operand:SI 1 "s_register_operand" "")
279890075Sobrien		     (match_operand:SI 2 "arm_rhs_operand" "")))]
279990075Sobrien  "TARGET_EITHER"
280090075Sobrien  "
280190075Sobrien  if (GET_CODE (operands[2]) == CONST_INT
280290075Sobrien      && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31)
280390075Sobrien    {
280490075Sobrien      emit_insn (gen_movsi (operands[0], const0_rtx));
280590075Sobrien      DONE;
280690075Sobrien    }
280790075Sobrien  "
280890075Sobrien)
280990075Sobrien
281090075Sobrien(define_insn "*thumb_lshrsi3"
281190075Sobrien  [(set (match_operand:SI              0 "register_operand" "=l,l")
281290075Sobrien	(lshiftrt:SI (match_operand:SI 1 "register_operand" "l,0")
281390075Sobrien		     (match_operand:SI 2 "nonmemory_operand" "N,l")))]
281490075Sobrien  "TARGET_THUMB"
281590075Sobrien  "lsr\\t%0, %1, %2"
281690075Sobrien  [(set_attr "length" "2")]
281790075Sobrien)
281890075Sobrien
281990075Sobrien(define_expand "rotlsi3"
282090075Sobrien  [(set (match_operand:SI              0 "s_register_operand" "")
282190075Sobrien	(rotatert:SI (match_operand:SI 1 "s_register_operand" "")
282290075Sobrien		     (match_operand:SI 2 "reg_or_int_operand" "")))]
282390075Sobrien  "TARGET_ARM"
282490075Sobrien  "
282590075Sobrien  if (GET_CODE (operands[2]) == CONST_INT)
282690075Sobrien    operands[2] = GEN_INT ((32 - INTVAL (operands[2])) % 32);
282790075Sobrien  else
282890075Sobrien    {
282990075Sobrien      rtx reg = gen_reg_rtx (SImode);
283090075Sobrien      emit_insn (gen_subsi3 (reg, GEN_INT (32), operands[2]));
283190075Sobrien      operands[2] = reg;
283290075Sobrien    }
283390075Sobrien  "
283490075Sobrien)
283590075Sobrien
283690075Sobrien(define_expand "rotrsi3"
283790075Sobrien  [(set (match_operand:SI              0 "s_register_operand" "")
283890075Sobrien	(rotatert:SI (match_operand:SI 1 "s_register_operand" "")
283990075Sobrien		     (match_operand:SI 2 "arm_rhs_operand" "")))]
284090075Sobrien  "TARGET_EITHER"
284190075Sobrien  "
284290075Sobrien  if (TARGET_ARM)
284390075Sobrien    {
284490075Sobrien      if (GET_CODE (operands[2]) == CONST_INT
284590075Sobrien          && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31)
284690075Sobrien        operands[2] = GEN_INT (INTVAL (operands[2]) % 32);
284790075Sobrien    }
284890075Sobrien  else /* TARGET_THUMB */
284990075Sobrien    {
285090075Sobrien      if (GET_CODE (operands [2]) == CONST_INT)
285190075Sobrien        operands [2] = force_reg (SImode, operands[2]);
285290075Sobrien    }
285390075Sobrien  "
285490075Sobrien)
285590075Sobrien
285690075Sobrien(define_insn "*thumb_rotrsi3"
285790075Sobrien  [(set (match_operand:SI              0 "register_operand" "=l")
285890075Sobrien	(rotatert:SI (match_operand:SI 1 "register_operand" "0")
285990075Sobrien		     (match_operand:SI 2 "register_operand" "l")))]
286090075Sobrien  "TARGET_THUMB"
286190075Sobrien  "ror\\t%0, %0, %2"
286290075Sobrien  [(set_attr "length" "2")]
286390075Sobrien)
286490075Sobrien
286590075Sobrien(define_insn "*arm_shiftsi3"
286690075Sobrien  [(set (match_operand:SI   0 "s_register_operand" "=r")
286790075Sobrien	(match_operator:SI  3 "shift_operator"
286890075Sobrien	 [(match_operand:SI 1 "s_register_operand"  "r")
286990075Sobrien	  (match_operand:SI 2 "reg_or_int_operand" "rM")]))]
287090075Sobrien  "TARGET_ARM"
287190075Sobrien  "mov%?\\t%0, %1%S3"
287290075Sobrien  [(set_attr "predicable" "yes")
287390075Sobrien   (set_attr "shift" "1")
2874169689Skan   (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
2875169689Skan		      (const_string "alu_shift")
2876169689Skan		      (const_string "alu_shift_reg")))]
287790075Sobrien)
287890075Sobrien
287990075Sobrien(define_insn "*shiftsi3_compare0"
288090075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
288190075Sobrien	(compare:CC_NOOV (match_operator:SI 3 "shift_operator"
288290075Sobrien			  [(match_operand:SI 1 "s_register_operand" "r")
288390075Sobrien			   (match_operand:SI 2 "arm_rhs_operand" "rM")])
288490075Sobrien			 (const_int 0)))
288590075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
288690075Sobrien	(match_op_dup 3 [(match_dup 1) (match_dup 2)]))]
288790075Sobrien  "TARGET_ARM"
288890075Sobrien  "mov%?s\\t%0, %1%S3"
288990075Sobrien  [(set_attr "conds" "set")
289090075Sobrien   (set_attr "shift" "1")
2891169689Skan   (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
2892169689Skan		      (const_string "alu_shift")
2893169689Skan		      (const_string "alu_shift_reg")))]
289490075Sobrien)
289590075Sobrien
289690075Sobrien(define_insn "*shiftsi3_compare0_scratch"
289790075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
289890075Sobrien	(compare:CC_NOOV (match_operator:SI 3 "shift_operator"
289990075Sobrien			  [(match_operand:SI 1 "s_register_operand" "r")
290090075Sobrien			   (match_operand:SI 2 "arm_rhs_operand" "rM")])
290190075Sobrien			 (const_int 0)))
290290075Sobrien   (clobber (match_scratch:SI 0 "=r"))]
290390075Sobrien  "TARGET_ARM"
290490075Sobrien  "mov%?s\\t%0, %1%S3"
290590075Sobrien  [(set_attr "conds" "set")
2906169689Skan   (set_attr "shift" "1")]
290790075Sobrien)
290890075Sobrien
290990075Sobrien(define_insn "*notsi_shiftsi"
291090075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
291190075Sobrien	(not:SI (match_operator:SI 3 "shift_operator"
291290075Sobrien		 [(match_operand:SI 1 "s_register_operand" "r")
291390075Sobrien		  (match_operand:SI 2 "arm_rhs_operand" "rM")])))]
291490075Sobrien  "TARGET_ARM"
291590075Sobrien  "mvn%?\\t%0, %1%S3"
291690075Sobrien  [(set_attr "predicable" "yes")
291790075Sobrien   (set_attr "shift" "1")
2918169689Skan   (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
2919169689Skan		      (const_string "alu_shift")
2920169689Skan		      (const_string "alu_shift_reg")))]
292190075Sobrien)
292290075Sobrien
292390075Sobrien(define_insn "*notsi_shiftsi_compare0"
292490075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
292590075Sobrien	(compare:CC_NOOV (not:SI (match_operator:SI 3 "shift_operator"
292690075Sobrien			  [(match_operand:SI 1 "s_register_operand" "r")
292790075Sobrien			   (match_operand:SI 2 "arm_rhs_operand" "rM")]))
292890075Sobrien			 (const_int 0)))
292990075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
293090075Sobrien	(not:SI (match_op_dup 3 [(match_dup 1) (match_dup 2)])))]
293190075Sobrien  "TARGET_ARM"
293290075Sobrien  "mvn%?s\\t%0, %1%S3"
293390075Sobrien  [(set_attr "conds" "set")
293490075Sobrien   (set_attr "shift" "1")
2935169689Skan   (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
2936169689Skan		      (const_string "alu_shift")
2937169689Skan		      (const_string "alu_shift_reg")))]
293890075Sobrien)
293990075Sobrien
294090075Sobrien(define_insn "*not_shiftsi_compare0_scratch"
294190075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
294290075Sobrien	(compare:CC_NOOV (not:SI (match_operator:SI 3 "shift_operator"
294390075Sobrien			  [(match_operand:SI 1 "s_register_operand" "r")
294490075Sobrien			   (match_operand:SI 2 "arm_rhs_operand" "rM")]))
294590075Sobrien			 (const_int 0)))
294690075Sobrien   (clobber (match_scratch:SI 0 "=r"))]
294790075Sobrien  "TARGET_ARM"
294890075Sobrien  "mvn%?s\\t%0, %1%S3"
294990075Sobrien  [(set_attr "conds" "set")
295090075Sobrien   (set_attr "shift" "1")
2951169689Skan   (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
2952169689Skan		      (const_string "alu_shift")
2953169689Skan		      (const_string "alu_shift_reg")))]
295490075Sobrien)
295590075Sobrien
295690075Sobrien;; We don't really have extzv, but defining this using shifts helps
295790075Sobrien;; to reduce register pressure later on.
295890075Sobrien
295990075Sobrien(define_expand "extzv"
296090075Sobrien  [(set (match_dup 4)
296190075Sobrien	(ashift:SI (match_operand:SI   1 "register_operand" "")
296290075Sobrien		   (match_operand:SI   2 "const_int_operand" "")))
296390075Sobrien   (set (match_operand:SI              0 "register_operand" "")
296490075Sobrien	(lshiftrt:SI (match_dup 4)
296590075Sobrien		     (match_operand:SI 3 "const_int_operand" "")))]
296690075Sobrien  "TARGET_THUMB"
296790075Sobrien  "
296890075Sobrien  {
296990075Sobrien    HOST_WIDE_INT lshift = 32 - INTVAL (operands[2]) - INTVAL (operands[3]);
297090075Sobrien    HOST_WIDE_INT rshift = 32 - INTVAL (operands[2]);
297190075Sobrien    
297290075Sobrien    operands[3] = GEN_INT (rshift);
297390075Sobrien    
297490075Sobrien    if (lshift == 0)
297590075Sobrien      {
297690075Sobrien        emit_insn (gen_lshrsi3 (operands[0], operands[1], operands[3]));
297790075Sobrien        DONE;
297890075Sobrien      }
297990075Sobrien      
298090075Sobrien    operands[2] = GEN_INT (lshift);
298190075Sobrien    operands[4] = gen_reg_rtx (SImode);
298290075Sobrien  }"
298390075Sobrien)
298490075Sobrien
298590075Sobrien
298690075Sobrien;; Unary arithmetic insns
298790075Sobrien
298890075Sobrien(define_expand "negdi2"
298990075Sobrien [(parallel
299090075Sobrien   [(set (match_operand:DI          0 "s_register_operand" "")
299190075Sobrien	  (neg:DI (match_operand:DI 1 "s_register_operand" "")))
299290075Sobrien    (clobber (reg:CC CC_REGNUM))])]
299390075Sobrien  "TARGET_EITHER"
299490075Sobrien  "
299590075Sobrien  if (TARGET_THUMB)
299690075Sobrien    {
299790075Sobrien      if (GET_CODE (operands[1]) != REG)
299890075Sobrien        operands[1] = force_reg (SImode, operands[1]);
299990075Sobrien     }
300090075Sobrien  "
300190075Sobrien)
300290075Sobrien
300390075Sobrien;; The constraints here are to prevent a *partial* overlap (where %Q0 == %R1).
300490075Sobrien;; The second alternative is to allow the common case of a *full* overlap.
300590075Sobrien(define_insn "*arm_negdi2"
300690075Sobrien  [(set (match_operand:DI         0 "s_register_operand" "=&r,r")
300790075Sobrien	(neg:DI (match_operand:DI 1 "s_register_operand"  "?r,0")))
300890075Sobrien   (clobber (reg:CC CC_REGNUM))]
300990075Sobrien  "TARGET_ARM"
301090075Sobrien  "rsbs\\t%Q0, %Q1, #0\;rsc\\t%R0, %R1, #0"
301190075Sobrien  [(set_attr "conds" "clob")
301290075Sobrien   (set_attr "length" "8")]
301390075Sobrien)
301490075Sobrien
301590075Sobrien(define_insn "*thumb_negdi2"
301690075Sobrien  [(set (match_operand:DI         0 "register_operand" "=&l")
301790075Sobrien	(neg:DI (match_operand:DI 1 "register_operand"   "l")))
301890075Sobrien   (clobber (reg:CC CC_REGNUM))]
301990075Sobrien  "TARGET_THUMB"
302090075Sobrien  "mov\\t%R0, #0\;neg\\t%Q0, %Q1\;sbc\\t%R0, %R1"
302190075Sobrien  [(set_attr "length" "6")]
302290075Sobrien)
302390075Sobrien
302490075Sobrien(define_expand "negsi2"
302590075Sobrien  [(set (match_operand:SI         0 "s_register_operand" "")
302690075Sobrien	(neg:SI (match_operand:SI 1 "s_register_operand" "")))]
302790075Sobrien  "TARGET_EITHER"
302890075Sobrien  ""
302990075Sobrien)
303090075Sobrien
303190075Sobrien(define_insn "*arm_negsi2"
303290075Sobrien  [(set (match_operand:SI         0 "s_register_operand" "=r")
303390075Sobrien	(neg:SI (match_operand:SI 1 "s_register_operand" "r")))]
303490075Sobrien  "TARGET_ARM"
303590075Sobrien  "rsb%?\\t%0, %1, #0"
303690075Sobrien  [(set_attr "predicable" "yes")]
303790075Sobrien)
303890075Sobrien
303990075Sobrien(define_insn "*thumb_negsi2"
304090075Sobrien  [(set (match_operand:SI         0 "register_operand" "=l")
304190075Sobrien	(neg:SI (match_operand:SI 1 "register_operand" "l")))]
304290075Sobrien  "TARGET_THUMB"
304390075Sobrien  "neg\\t%0, %1"
304490075Sobrien  [(set_attr "length" "2")]
304590075Sobrien)
304690075Sobrien
3047132718Skan(define_expand "negsf2"
3048132718Skan  [(set (match_operand:SF         0 "s_register_operand" "")
3049132718Skan	(neg:SF (match_operand:SF 1 "s_register_operand" "")))]
3050169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
3051132718Skan  ""
305290075Sobrien)
305390075Sobrien
3054132718Skan(define_expand "negdf2"
3055132718Skan  [(set (match_operand:DF         0 "s_register_operand" "")
3056132718Skan	(neg:DF (match_operand:DF 1 "s_register_operand" "")))]
3057169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
3058132718Skan  "")
305990075Sobrien
306090075Sobrien;; abssi2 doesn't really clobber the condition codes if a different register
306190075Sobrien;; is being set.  To keep things simple, assume during rtl manipulations that
306290075Sobrien;; it does, but tell the final scan operator the truth.  Similarly for
306390075Sobrien;; (neg (abs...))
306490075Sobrien
3065132718Skan(define_expand "abssi2"
3066132718Skan  [(parallel
3067132718Skan    [(set (match_operand:SI         0 "s_register_operand" "")
3068132718Skan	  (abs:SI (match_operand:SI 1 "s_register_operand" "")))
3069132718Skan     (clobber (reg:CC CC_REGNUM))])]
3070132718Skan  "TARGET_ARM"
3071132718Skan  "")
3072132718Skan
3073132718Skan(define_insn "*arm_abssi2"
307490075Sobrien  [(set (match_operand:SI         0 "s_register_operand" "=r,&r")
307590075Sobrien	(abs:SI (match_operand:SI 1 "s_register_operand" "0,r")))
307690075Sobrien   (clobber (reg:CC CC_REGNUM))]
307790075Sobrien  "TARGET_ARM"
307890075Sobrien  "@
307990075Sobrien   cmp\\t%0, #0\;rsblt\\t%0, %0, #0
308090075Sobrien   eor%?\\t%0, %1, %1, asr #31\;sub%?\\t%0, %0, %1, asr #31"
308190075Sobrien  [(set_attr "conds" "clob,*")
308290075Sobrien   (set_attr "shift" "1")
308390075Sobrien   ;; predicable can't be set based on the variant, so left as no
308490075Sobrien   (set_attr "length" "8")]
308590075Sobrien)
308690075Sobrien
308790075Sobrien(define_insn "*neg_abssi2"
308890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,&r")
308990075Sobrien	(neg:SI (abs:SI (match_operand:SI 1 "s_register_operand" "0,r"))))
309090075Sobrien   (clobber (reg:CC CC_REGNUM))]
309190075Sobrien  "TARGET_ARM"
309290075Sobrien  "@
309390075Sobrien   cmp\\t%0, #0\;rsbgt\\t%0, %0, #0
309490075Sobrien   eor%?\\t%0, %1, %1, asr #31\;rsb%?\\t%0, %0, %1, asr #31"
309590075Sobrien  [(set_attr "conds" "clob,*")
309690075Sobrien   (set_attr "shift" "1")
309790075Sobrien   ;; predicable can't be set based on the variant, so left as no
309890075Sobrien   (set_attr "length" "8")]
309990075Sobrien)
310090075Sobrien
3101132718Skan(define_expand "abssf2"
3102132718Skan  [(set (match_operand:SF         0 "s_register_operand" "")
3103132718Skan	(abs:SF (match_operand:SF 1 "s_register_operand" "")))]
3104169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT"
3105132718Skan  "")
310690075Sobrien
3107132718Skan(define_expand "absdf2"
3108132718Skan  [(set (match_operand:DF         0 "s_register_operand" "")
3109132718Skan	(abs:DF (match_operand:DF 1 "s_register_operand" "")))]
3110169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT"
3111132718Skan  "")
311290075Sobrien
3113132718Skan(define_expand "sqrtsf2"
3114132718Skan  [(set (match_operand:SF 0 "s_register_operand" "")
3115132718Skan	(sqrt:SF (match_operand:SF 1 "s_register_operand" "")))]
3116169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
3117132718Skan  "")
311890075Sobrien
3119132718Skan(define_expand "sqrtdf2"
3120132718Skan  [(set (match_operand:DF 0 "s_register_operand" "")
3121132718Skan	(sqrt:DF (match_operand:DF 1 "s_register_operand" "")))]
3122169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
3123132718Skan  "")
312490075Sobrien
312590075Sobrien(define_insn_and_split "one_cmpldi2"
312690075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
312790075Sobrien	(not:DI (match_operand:DI 1 "s_register_operand" "?r,0")))]
312890075Sobrien  "TARGET_ARM"
312990075Sobrien  "#"
313090075Sobrien  "TARGET_ARM && reload_completed"
313190075Sobrien  [(set (match_dup 0) (not:SI (match_dup 1)))
313290075Sobrien   (set (match_dup 2) (not:SI (match_dup 3)))]
313390075Sobrien  "
313490075Sobrien  {
313590075Sobrien    operands[2] = gen_highpart (SImode, operands[0]);
313690075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
313790075Sobrien    operands[3] = gen_highpart (SImode, operands[1]);
313890075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
313990075Sobrien  }"
314090075Sobrien  [(set_attr "length" "8")
314190075Sobrien   (set_attr "predicable" "yes")]
314290075Sobrien)
314390075Sobrien
314490075Sobrien(define_expand "one_cmplsi2"
314590075Sobrien  [(set (match_operand:SI         0 "s_register_operand" "")
314690075Sobrien	(not:SI (match_operand:SI 1 "s_register_operand" "")))]
314790075Sobrien  "TARGET_EITHER"
314890075Sobrien  ""
314990075Sobrien)
315090075Sobrien
315190075Sobrien(define_insn "*arm_one_cmplsi2"
315290075Sobrien  [(set (match_operand:SI         0 "s_register_operand" "=r")
315390075Sobrien	(not:SI (match_operand:SI 1 "s_register_operand"  "r")))]
315490075Sobrien  "TARGET_ARM"
315590075Sobrien  "mvn%?\\t%0, %1"
315690075Sobrien  [(set_attr "predicable" "yes")]
315790075Sobrien)
315890075Sobrien
315990075Sobrien(define_insn "*thumb_one_cmplsi2"
316090075Sobrien  [(set (match_operand:SI         0 "register_operand" "=l")
316190075Sobrien	(not:SI (match_operand:SI 1 "register_operand"  "l")))]
316290075Sobrien  "TARGET_THUMB"
316390075Sobrien  "mvn\\t%0, %1"
316490075Sobrien  [(set_attr "length" "2")]
316590075Sobrien)
316690075Sobrien
316790075Sobrien(define_insn "*notsi_compare0"
316890075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
316990075Sobrien	(compare:CC_NOOV (not:SI (match_operand:SI 1 "s_register_operand" "r"))
317090075Sobrien			 (const_int 0)))
317190075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
317290075Sobrien	(not:SI (match_dup 1)))]
317390075Sobrien  "TARGET_ARM"
317490075Sobrien  "mvn%?s\\t%0, %1"
317590075Sobrien  [(set_attr "conds" "set")]
317690075Sobrien)
317790075Sobrien
317890075Sobrien(define_insn "*notsi_compare0_scratch"
317990075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
318090075Sobrien	(compare:CC_NOOV (not:SI (match_operand:SI 1 "s_register_operand" "r"))
318190075Sobrien			 (const_int 0)))
318290075Sobrien   (clobber (match_scratch:SI 0 "=r"))]
318390075Sobrien  "TARGET_ARM"
318490075Sobrien  "mvn%?s\\t%0, %1"
318590075Sobrien  [(set_attr "conds" "set")]
318690075Sobrien)
318790075Sobrien
318890075Sobrien;; Fixed <--> Floating conversion insns
318990075Sobrien
3190132718Skan(define_expand "floatsisf2"
3191132718Skan  [(set (match_operand:SF           0 "s_register_operand" "")
3192132718Skan	(float:SF (match_operand:SI 1 "s_register_operand" "")))]
3193169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT"
3194132718Skan  "
3195169689Skan  if (TARGET_MAVERICK)
3196132718Skan    {
3197132718Skan      emit_insn (gen_cirrus_floatsisf2 (operands[0], operands[1]));
3198132718Skan      DONE;
3199132718Skan    }
3200132718Skan")
320190075Sobrien
3202132718Skan(define_expand "floatsidf2"
3203132718Skan  [(set (match_operand:DF           0 "s_register_operand" "")
3204132718Skan	(float:DF (match_operand:SI 1 "s_register_operand" "")))]
3205169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT"
3206132718Skan  "
3207169689Skan  if (TARGET_MAVERICK)
3208132718Skan    {
3209132718Skan      emit_insn (gen_cirrus_floatsidf2 (operands[0], operands[1]));
3210132718Skan      DONE;
3211132718Skan    }
3212132718Skan")
321390075Sobrien
3214132718Skan(define_expand "fix_truncsfsi2"
3215132718Skan  [(set (match_operand:SI         0 "s_register_operand" "")
3216132718Skan	(fix:SI (fix:SF (match_operand:SF 1 "s_register_operand"  ""))))]
3217169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT"
3218132718Skan  "
3219169689Skan  if (TARGET_MAVERICK)
3220132718Skan    {
3221132718Skan      if (!cirrus_fp_register (operands[0], SImode))
3222132718Skan        operands[0] = force_reg (SImode, operands[0]);
3223132718Skan      if (!cirrus_fp_register (operands[1], SFmode))
3224132718Skan        operands[1] = force_reg (SFmode, operands[0]);
3225132718Skan      emit_insn (gen_cirrus_truncsfsi2 (operands[0], operands[1]));
3226132718Skan      DONE;
3227132718Skan    }
3228132718Skan")
322990075Sobrien
3230132718Skan(define_expand "fix_truncdfsi2"
3231132718Skan  [(set (match_operand:SI         0 "s_register_operand" "")
3232132718Skan	(fix:SI (fix:DF (match_operand:DF 1 "s_register_operand"  ""))))]
3233169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT"
3234132718Skan  "
3235169689Skan  if (TARGET_MAVERICK)
3236132718Skan    {
3237132718Skan      if (!cirrus_fp_register (operands[1], DFmode))
3238132718Skan        operands[1] = force_reg (DFmode, operands[0]);
3239132718Skan      emit_insn (gen_cirrus_truncdfsi2 (operands[0], operands[1]));
3240132718Skan      DONE;
3241132718Skan    }
3242132718Skan")
324390075Sobrien
324490075Sobrien;; Truncation insns
324590075Sobrien
3246132718Skan(define_expand "truncdfsf2"
3247132718Skan  [(set (match_operand:SF  0 "s_register_operand" "")
324890075Sobrien	(float_truncate:SF
3249132718Skan 	 (match_operand:DF 1 "s_register_operand" "")))]
3250169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT"
3251132718Skan  ""
325290075Sobrien)
325390075Sobrien
325490075Sobrien;; Zero and sign extension instructions.
325590075Sobrien
325690075Sobrien(define_insn "zero_extendsidi2"
325790075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=r")
325890075Sobrien        (zero_extend:DI (match_operand:SI 1 "s_register_operand" "r")))]
325990075Sobrien  "TARGET_ARM"
326090075Sobrien  "*
326190075Sobrien    if (REGNO (operands[1])
326290075Sobrien        != REGNO (operands[0]) + (WORDS_BIG_ENDIAN ? 1 : 0))
326390075Sobrien      output_asm_insn (\"mov%?\\t%Q0, %1\", operands);
326490075Sobrien    return \"mov%?\\t%R0, #0\";
326590075Sobrien  "
326690075Sobrien  [(set_attr "length" "8")
326790075Sobrien   (set_attr "predicable" "yes")]
326890075Sobrien)
326990075Sobrien
327090075Sobrien(define_insn "zero_extendqidi2"
327190075Sobrien  [(set (match_operand:DI                 0 "s_register_operand"  "=r,r")
327290075Sobrien	(zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
327390075Sobrien  "TARGET_ARM"
327490075Sobrien  "@
327590075Sobrien   and%?\\t%Q0, %1, #255\;mov%?\\t%R0, #0
327690075Sobrien   ldr%?b\\t%Q0, %1\;mov%?\\t%R0, #0"
327790075Sobrien  [(set_attr "length" "8")
327890075Sobrien   (set_attr "predicable" "yes")
3279169689Skan   (set_attr "type" "*,load_byte")
328090075Sobrien   (set_attr "pool_range" "*,4092")
328190075Sobrien   (set_attr "neg_pool_range" "*,4084")]
328290075Sobrien)
328390075Sobrien
328490075Sobrien(define_insn "extendsidi2"
328590075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=r")
328690075Sobrien        (sign_extend:DI (match_operand:SI 1 "s_register_operand" "r")))]
328790075Sobrien  "TARGET_ARM"
328890075Sobrien  "*
328990075Sobrien    if (REGNO (operands[1])
329090075Sobrien        != REGNO (operands[0]) + (WORDS_BIG_ENDIAN ? 1 : 0))
329190075Sobrien      output_asm_insn (\"mov%?\\t%Q0, %1\", operands);
329290075Sobrien    return \"mov%?\\t%R0, %Q0, asr #31\";
329390075Sobrien  "
329490075Sobrien  [(set_attr "length" "8")
329590075Sobrien   (set_attr "shift" "1")
329690075Sobrien   (set_attr "predicable" "yes")]
329790075Sobrien)
329890075Sobrien
329990075Sobrien(define_expand "zero_extendhisi2"
330090075Sobrien  [(set (match_dup 2)
330190075Sobrien	(ashift:SI (match_operand:HI 1 "nonimmediate_operand" "")
330290075Sobrien		   (const_int 16)))
330390075Sobrien   (set (match_operand:SI 0 "s_register_operand" "")
330490075Sobrien	(lshiftrt:SI (match_dup 2) (const_int 16)))]
330590075Sobrien  "TARGET_EITHER"
330690075Sobrien  "
330790075Sobrien  {
3308169689Skan    if ((TARGET_THUMB || arm_arch4) && GET_CODE (operands[1]) == MEM)
330990075Sobrien      {
3310169689Skan	emit_insn (gen_rtx_SET (VOIDmode, operands[0],
3311169689Skan				gen_rtx_ZERO_EXTEND (SImode, operands[1])));
3312169689Skan	DONE;
331390075Sobrien      }
3314169689Skan
3315169689Skan    if (TARGET_ARM && GET_CODE (operands[1]) == MEM)
331690075Sobrien      {
3317169689Skan	emit_insn (gen_movhi_bytes (operands[0], operands[1]));
3318169689Skan	DONE;
3319169689Skan      }
332090075Sobrien
3321169689Skan    if (!s_register_operand (operands[1], HImode))
3322169689Skan      operands[1] = copy_to_mode_reg (HImode, operands[1]);
332390075Sobrien
3324169689Skan    if (arm_arch6)
3325169689Skan      {
3326169689Skan	emit_insn (gen_rtx_SET (VOIDmode, operands[0],
3327169689Skan				gen_rtx_ZERO_EXTEND (SImode, operands[1])));
3328169689Skan	DONE;
3329169689Skan      }
333090075Sobrien
3331169689Skan    operands[1] = gen_lowpart (SImode, operands[1]);
3332169689Skan    operands[2] = gen_reg_rtx (SImode);
333390075Sobrien  }"
333490075Sobrien)
333590075Sobrien
333690075Sobrien(define_insn "*thumb_zero_extendhisi2"
3337169689Skan  [(set (match_operand:SI 0 "register_operand" "=l")
3338169689Skan	(zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
3339169689Skan  "TARGET_THUMB && !arm_arch6"
334090075Sobrien  "*
334190075Sobrien  rtx mem = XEXP (operands[1], 0);
334290075Sobrien
334390075Sobrien  if (GET_CODE (mem) == CONST)
334490075Sobrien    mem = XEXP (mem, 0);
334590075Sobrien    
334690075Sobrien  if (GET_CODE (mem) == LABEL_REF)
334790075Sobrien    return \"ldr\\t%0, %1\";
334890075Sobrien    
334990075Sobrien  if (GET_CODE (mem) == PLUS)
335090075Sobrien    {
335190075Sobrien      rtx a = XEXP (mem, 0);
335290075Sobrien      rtx b = XEXP (mem, 1);
335390075Sobrien
335490075Sobrien      /* This can happen due to bugs in reload.  */
335590075Sobrien      if (GET_CODE (a) == REG && REGNO (a) == SP_REGNUM)
335690075Sobrien        {
335790075Sobrien          rtx ops[2];
335890075Sobrien          ops[0] = operands[0];
335990075Sobrien          ops[1] = a;
336090075Sobrien      
336190075Sobrien          output_asm_insn (\"mov	%0, %1\", ops);
336290075Sobrien
336390075Sobrien          XEXP (mem, 0) = operands[0];
336490075Sobrien       }
336590075Sobrien
336690075Sobrien      else if (   GET_CODE (a) == LABEL_REF
336790075Sobrien	       && GET_CODE (b) == CONST_INT)
336890075Sobrien        return \"ldr\\t%0, %1\";
336990075Sobrien    }
337090075Sobrien    
337190075Sobrien  return \"ldrh\\t%0, %1\";
337290075Sobrien  "
337390075Sobrien  [(set_attr "length" "4")
3374169689Skan   (set_attr "type" "load_byte")
337590075Sobrien   (set_attr "pool_range" "60")]
337690075Sobrien)
337790075Sobrien
3378169689Skan(define_insn "*thumb_zero_extendhisi2_v6"
3379169689Skan  [(set (match_operand:SI 0 "register_operand" "=l,l")
3380169689Skan	(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "l,m")))]
3381169689Skan  "TARGET_THUMB && arm_arch6"
3382169689Skan  "*
3383169689Skan  rtx mem;
3384169689Skan
3385169689Skan  if (which_alternative == 0)
3386169689Skan    return \"uxth\\t%0, %1\";
3387169689Skan
3388169689Skan  mem = XEXP (operands[1], 0);
3389169689Skan
3390169689Skan  if (GET_CODE (mem) == CONST)
3391169689Skan    mem = XEXP (mem, 0);
3392169689Skan    
3393169689Skan  if (GET_CODE (mem) == LABEL_REF)
3394169689Skan    return \"ldr\\t%0, %1\";
3395169689Skan    
3396169689Skan  if (GET_CODE (mem) == PLUS)
3397169689Skan    {
3398169689Skan      rtx a = XEXP (mem, 0);
3399169689Skan      rtx b = XEXP (mem, 1);
3400169689Skan
3401169689Skan      /* This can happen due to bugs in reload.  */
3402169689Skan      if (GET_CODE (a) == REG && REGNO (a) == SP_REGNUM)
3403169689Skan        {
3404169689Skan          rtx ops[2];
3405169689Skan          ops[0] = operands[0];
3406169689Skan          ops[1] = a;
3407169689Skan      
3408169689Skan          output_asm_insn (\"mov	%0, %1\", ops);
3409169689Skan
3410169689Skan          XEXP (mem, 0) = operands[0];
3411169689Skan       }
3412169689Skan
3413169689Skan      else if (   GET_CODE (a) == LABEL_REF
3414169689Skan	       && GET_CODE (b) == CONST_INT)
3415169689Skan        return \"ldr\\t%0, %1\";
3416169689Skan    }
3417169689Skan    
3418169689Skan  return \"ldrh\\t%0, %1\";
3419169689Skan  "
3420169689Skan  [(set_attr "length" "2,4")
3421169689Skan   (set_attr "type" "alu_shift,load_byte")
3422169689Skan   (set_attr "pool_range" "*,60")]
3423169689Skan)
3424169689Skan
342590075Sobrien(define_insn "*arm_zero_extendhisi2"
3426169689Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
3427169689Skan	(zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
3428169689Skan  "TARGET_ARM && arm_arch4 && !arm_arch6"
342990075Sobrien  "ldr%?h\\t%0, %1"
3430169689Skan  [(set_attr "type" "load_byte")
343190075Sobrien   (set_attr "predicable" "yes")
343290075Sobrien   (set_attr "pool_range" "256")
343390075Sobrien   (set_attr "neg_pool_range" "244")]
343490075Sobrien)
343590075Sobrien
3436169689Skan(define_insn "*arm_zero_extendhisi2_v6"
3437169689Skan  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
3438169689Skan	(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
3439169689Skan  "TARGET_ARM && arm_arch6"
3440169689Skan  "@
3441169689Skan   uxth%?\\t%0, %1
3442169689Skan   ldr%?h\\t%0, %1"
3443169689Skan  [(set_attr "type" "alu_shift,load_byte")
3444169689Skan   (set_attr "predicable" "yes")
3445169689Skan   (set_attr "pool_range" "*,256")
3446169689Skan   (set_attr "neg_pool_range" "*,244")]
344790075Sobrien)
344890075Sobrien
3449169689Skan(define_insn "*arm_zero_extendhisi2addsi"
3450169689Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
3451169689Skan	(plus:SI (zero_extend:SI (match_operand:HI 1 "s_register_operand" "r"))
3452169689Skan		 (match_operand:SI 2 "s_register_operand" "r")))]
3453169689Skan  "TARGET_ARM && arm_arch6"
3454169689Skan  "uxtah%?\\t%0, %2, %1"
3455169689Skan  [(set_attr "type" "alu_shift")
3456169689Skan   (set_attr "predicable" "yes")]
345790075Sobrien)
345890075Sobrien
345990075Sobrien(define_expand "zero_extendqisi2"
346090075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
346190075Sobrien	(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
346290075Sobrien  "TARGET_EITHER"
346390075Sobrien  "
3464169689Skan  if (!arm_arch6 && GET_CODE (operands[1]) != MEM)
346590075Sobrien    {
346690075Sobrien      if (TARGET_ARM)
346790075Sobrien        {
346890075Sobrien          emit_insn (gen_andsi3 (operands[0],
346990075Sobrien				 gen_lowpart (SImode, operands[1]),
347090075Sobrien			         GEN_INT (255)));
347190075Sobrien        }
347290075Sobrien      else /* TARGET_THUMB */
347390075Sobrien        {
347490075Sobrien          rtx temp = gen_reg_rtx (SImode);
347590075Sobrien	  rtx ops[3];
347690075Sobrien	  
347790075Sobrien          operands[1] = copy_to_mode_reg (QImode, operands[1]);
347890075Sobrien          operands[1] = gen_lowpart (SImode, operands[1]);
347990075Sobrien
348090075Sobrien	  ops[0] = temp;
348190075Sobrien	  ops[1] = operands[1];
348290075Sobrien	  ops[2] = GEN_INT (24);
348390075Sobrien
348490075Sobrien	  emit_insn (gen_rtx_SET (VOIDmode, ops[0],
348590075Sobrien				  gen_rtx_ASHIFT (SImode, ops[1], ops[2])));
348690075Sobrien	  
348790075Sobrien          ops[0] = operands[0];
348890075Sobrien	  ops[1] = temp;
348990075Sobrien	  ops[2] = GEN_INT (24);
349090075Sobrien
349190075Sobrien	  emit_insn (gen_rtx_SET (VOIDmode, ops[0],
349290075Sobrien				  gen_rtx_LSHIFTRT (SImode, ops[1], ops[2])));
349390075Sobrien	}
349490075Sobrien      DONE;
349590075Sobrien    }
349690075Sobrien  "
349790075Sobrien)
349890075Sobrien
349990075Sobrien(define_insn "*thumb_zero_extendqisi2"
3500169689Skan  [(set (match_operand:SI 0 "register_operand" "=l")
3501169689Skan	(zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
3502169689Skan  "TARGET_THUMB && !arm_arch6"
350390075Sobrien  "ldrb\\t%0, %1"
350490075Sobrien  [(set_attr "length" "2")
3505169689Skan   (set_attr "type" "load_byte")
350690075Sobrien   (set_attr "pool_range" "32")]
350790075Sobrien)
350890075Sobrien
3509169689Skan(define_insn "*thumb_zero_extendqisi2_v6"
3510169689Skan  [(set (match_operand:SI 0 "register_operand" "=l,l")
3511169689Skan	(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "l,m")))]
3512169689Skan  "TARGET_THUMB && arm_arch6"
3513169689Skan  "@
3514169689Skan   uxtb\\t%0, %1
3515169689Skan   ldrb\\t%0, %1"
3516169689Skan  [(set_attr "length" "2,2")
3517169689Skan   (set_attr "type" "alu_shift,load_byte")
3518169689Skan   (set_attr "pool_range" "*,32")]
3519169689Skan)
3520169689Skan
352190075Sobrien(define_insn "*arm_zero_extendqisi2"
3522169689Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
3523169689Skan	(zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
3524169689Skan  "TARGET_ARM && !arm_arch6"
352590075Sobrien  "ldr%?b\\t%0, %1\\t%@ zero_extendqisi2"
3526169689Skan  [(set_attr "type" "load_byte")
352790075Sobrien   (set_attr "predicable" "yes")
352890075Sobrien   (set_attr "pool_range" "4096")
352990075Sobrien   (set_attr "neg_pool_range" "4084")]
353090075Sobrien)
353190075Sobrien
3532169689Skan(define_insn "*arm_zero_extendqisi2_v6"
3533169689Skan  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
3534169689Skan	(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
3535169689Skan  "TARGET_ARM && arm_arch6"
3536169689Skan  "@
3537169689Skan   uxtb%?\\t%0, %1
3538169689Skan   ldr%?b\\t%0, %1\\t%@ zero_extendqisi2"
3539169689Skan  [(set_attr "type" "alu_shift,load_byte")
3540169689Skan   (set_attr "predicable" "yes")
3541169689Skan   (set_attr "pool_range" "*,4096")
3542169689Skan   (set_attr "neg_pool_range" "*,4084")]
3543169689Skan)
3544169689Skan
3545169689Skan(define_insn "*arm_zero_extendqisi2addsi"
3546169689Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
3547169689Skan	(plus:SI (zero_extend:SI (match_operand:QI 1 "s_register_operand" "r"))
3548169689Skan		 (match_operand:SI 2 "s_register_operand" "r")))]
3549169689Skan  "TARGET_ARM && arm_arch6"
3550169689Skan  "uxtab%?\\t%0, %2, %1"
3551169689Skan  [(set_attr "predicable" "yes")
3552169689Skan   (set_attr "type" "alu_shift")]
3553169689Skan)
3554169689Skan
355590075Sobrien(define_split
355690075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
355790075Sobrien	(zero_extend:SI (subreg:QI (match_operand:SI 1 "" "") 0)))
355890075Sobrien   (clobber (match_operand:SI 2 "s_register_operand" ""))]
3559102780Skan  "TARGET_ARM && (GET_CODE (operands[1]) != MEM) && ! BYTES_BIG_ENDIAN"
356090075Sobrien  [(set (match_dup 2) (match_dup 1))
356190075Sobrien   (set (match_dup 0) (and:SI (match_dup 2) (const_int 255)))]
356290075Sobrien  ""
356390075Sobrien)
356490075Sobrien
3565169689Skan(define_split
3566169689Skan  [(set (match_operand:SI 0 "s_register_operand" "")
3567169689Skan	(zero_extend:SI (subreg:QI (match_operand:SI 1 "" "") 3)))
3568169689Skan   (clobber (match_operand:SI 2 "s_register_operand" ""))]
3569169689Skan  "TARGET_ARM && (GET_CODE (operands[1]) != MEM) && BYTES_BIG_ENDIAN"
3570169689Skan  [(set (match_dup 2) (match_dup 1))
3571169689Skan   (set (match_dup 0) (and:SI (match_dup 2) (const_int 255)))]
3572169689Skan  ""
3573169689Skan)
3574169689Skan
357590075Sobrien(define_insn "*compareqi_eq0"
357690075Sobrien  [(set (reg:CC_Z CC_REGNUM)
357790075Sobrien	(compare:CC_Z (match_operand:QI 0 "s_register_operand" "r")
357890075Sobrien			 (const_int 0)))]
357990075Sobrien  "TARGET_ARM"
358090075Sobrien  "tst\\t%0, #255"
358190075Sobrien  [(set_attr "conds" "set")]
358290075Sobrien)
358390075Sobrien
358490075Sobrien(define_expand "extendhisi2"
358590075Sobrien  [(set (match_dup 2)
358690075Sobrien	(ashift:SI (match_operand:HI 1 "nonimmediate_operand" "")
358790075Sobrien		   (const_int 16)))
358890075Sobrien   (set (match_operand:SI 0 "s_register_operand" "")
358990075Sobrien	(ashiftrt:SI (match_dup 2)
359090075Sobrien		     (const_int 16)))]
359190075Sobrien  "TARGET_EITHER"
359290075Sobrien  "
359390075Sobrien  {
3594169689Skan    if (GET_CODE (operands[1]) == MEM)
359590075Sobrien      {
3596169689Skan	if (TARGET_THUMB)
3597169689Skan	  {
3598169689Skan	    emit_insn (gen_thumb_extendhisi2 (operands[0], operands[1]));
3599169689Skan	    DONE;
3600169689Skan          }
3601169689Skan	else if (arm_arch4)
3602169689Skan	  {
3603169689Skan	    emit_insn (gen_rtx_SET (VOIDmode, operands[0],
3604169689Skan		       gen_rtx_SIGN_EXTEND (SImode, operands[1])));
3605169689Skan	    DONE;
3606169689Skan	  }
360790075Sobrien      }
360890075Sobrien
3609169689Skan    if (TARGET_ARM && GET_CODE (operands[1]) == MEM)
361090075Sobrien      {
361190075Sobrien        emit_insn (gen_extendhisi2_mem (operands[0], operands[1]));
361290075Sobrien        DONE;
361390075Sobrien      }
3614169689Skan
361590075Sobrien    if (!s_register_operand (operands[1], HImode))
361690075Sobrien      operands[1] = copy_to_mode_reg (HImode, operands[1]);
361790075Sobrien
3618169689Skan    if (arm_arch6)
361990075Sobrien      {
3620169689Skan	if (TARGET_THUMB)
3621169689Skan	  emit_insn (gen_thumb_extendhisi2 (operands[0], operands[1]));
3622169689Skan	else
3623169689Skan	  emit_insn (gen_rtx_SET (VOIDmode, operands[0],
3624169689Skan		     gen_rtx_SIGN_EXTEND (SImode, operands[1])));
3625169689Skan
362690075Sobrien	DONE;
362790075Sobrien      }
3628169689Skan
3629169689Skan    operands[1] = gen_lowpart (SImode, operands[1]);
3630169689Skan    operands[2] = gen_reg_rtx (SImode);
363190075Sobrien  }"
363290075Sobrien)
363390075Sobrien
3634169689Skan(define_insn "thumb_extendhisi2"
3635169689Skan  [(set (match_operand:SI 0 "register_operand" "=l")
3636169689Skan	(sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))
3637169689Skan   (clobber (match_scratch:SI 2 "=&l"))]
3638169689Skan  "TARGET_THUMB && !arm_arch6"
363990075Sobrien  "*
364090075Sobrien  {
364190075Sobrien    rtx ops[4];
364290075Sobrien    rtx mem = XEXP (operands[1], 0);
364390075Sobrien
364490075Sobrien    /* This code used to try to use 'V', and fix the address only if it was
364590075Sobrien       offsettable, but this fails for e.g. REG+48 because 48 is outside the
364690075Sobrien       range of QImode offsets, and offsettable_address_p does a QImode
364790075Sobrien       address check.  */
364890075Sobrien       
364990075Sobrien    if (GET_CODE (mem) == CONST)
365090075Sobrien      mem = XEXP (mem, 0);
365190075Sobrien    
365290075Sobrien    if (GET_CODE (mem) == LABEL_REF)
365390075Sobrien      return \"ldr\\t%0, %1\";
365490075Sobrien    
365590075Sobrien    if (GET_CODE (mem) == PLUS)
365690075Sobrien      {
365790075Sobrien        rtx a = XEXP (mem, 0);
365890075Sobrien        rtx b = XEXP (mem, 1);
365990075Sobrien
366090075Sobrien        if (GET_CODE (a) == LABEL_REF
366190075Sobrien	    && GET_CODE (b) == CONST_INT)
366290075Sobrien          return \"ldr\\t%0, %1\";
366390075Sobrien
366490075Sobrien        if (GET_CODE (b) == REG)
366590075Sobrien          return \"ldrsh\\t%0, %1\";
366690075Sobrien	  
366790075Sobrien        ops[1] = a;
366890075Sobrien        ops[2] = b;
366990075Sobrien      }
367090075Sobrien    else
367190075Sobrien      {
367290075Sobrien        ops[1] = mem;
367390075Sobrien        ops[2] = const0_rtx;
367490075Sobrien      }
367590075Sobrien
3676169689Skan    gcc_assert (GET_CODE (ops[1]) == REG);
3677169689Skan
367890075Sobrien    ops[0] = operands[0];
367990075Sobrien    ops[3] = operands[2];
368090075Sobrien    output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops);
368190075Sobrien    return \"\";
368290075Sobrien  }"
368390075Sobrien  [(set_attr "length" "4")
3684169689Skan   (set_attr "type" "load_byte")
368590075Sobrien   (set_attr "pool_range" "1020")]
368690075Sobrien)
368790075Sobrien
3688169689Skan;; We used to have an early-clobber on the scratch register here.
3689169689Skan;; However, there's a bug somewhere in reload which means that this
3690169689Skan;; can be partially ignored during spill allocation if the memory
3691169689Skan;; address also needs reloading; this causes us to die later on when
3692169689Skan;; we try to verify the operands.  Fortunately, we don't really need
3693169689Skan;; the early-clobber: we can always use operand 0 if operand 2
3694169689Skan;; overlaps the address.
3695169689Skan(define_insn "*thumb_extendhisi2_insn_v6"
3696169689Skan  [(set (match_operand:SI 0 "register_operand" "=l,l")
3697169689Skan	(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "l,m")))
3698169689Skan   (clobber (match_scratch:SI 2 "=X,l"))]
3699169689Skan  "TARGET_THUMB && arm_arch6"
3700169689Skan  "*
3701169689Skan  {
3702169689Skan    rtx ops[4];
3703169689Skan    rtx mem;
3704169689Skan
3705169689Skan    if (which_alternative == 0)
3706169689Skan      return \"sxth\\t%0, %1\";
3707169689Skan
3708169689Skan    mem = XEXP (operands[1], 0);
3709169689Skan
3710169689Skan    /* This code used to try to use 'V', and fix the address only if it was
3711169689Skan       offsettable, but this fails for e.g. REG+48 because 48 is outside the
3712169689Skan       range of QImode offsets, and offsettable_address_p does a QImode
3713169689Skan       address check.  */
3714169689Skan       
3715169689Skan    if (GET_CODE (mem) == CONST)
3716169689Skan      mem = XEXP (mem, 0);
3717169689Skan    
3718169689Skan    if (GET_CODE (mem) == LABEL_REF)
3719169689Skan      return \"ldr\\t%0, %1\";
3720169689Skan    
3721169689Skan    if (GET_CODE (mem) == PLUS)
3722169689Skan      {
3723169689Skan        rtx a = XEXP (mem, 0);
3724169689Skan        rtx b = XEXP (mem, 1);
3725169689Skan
3726169689Skan        if (GET_CODE (a) == LABEL_REF
3727169689Skan	    && GET_CODE (b) == CONST_INT)
3728169689Skan          return \"ldr\\t%0, %1\";
3729169689Skan
3730169689Skan        if (GET_CODE (b) == REG)
3731169689Skan          return \"ldrsh\\t%0, %1\";
3732169689Skan	  
3733169689Skan        ops[1] = a;
3734169689Skan        ops[2] = b;
3735169689Skan      }
3736169689Skan    else
3737169689Skan      {
3738169689Skan        ops[1] = mem;
3739169689Skan        ops[2] = const0_rtx;
3740169689Skan      }
3741169689Skan      
3742169689Skan    gcc_assert (GET_CODE (ops[1]) == REG);
3743169689Skan
3744169689Skan    ops[0] = operands[0];
3745169689Skan    if (reg_mentioned_p (operands[2], ops[1]))
3746169689Skan      ops[3] = ops[0];
3747169689Skan    else
3748169689Skan      ops[3] = operands[2];
3749169689Skan    output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops);
3750169689Skan    return \"\";
3751169689Skan  }"
3752169689Skan  [(set_attr "length" "2,4")
3753169689Skan   (set_attr "type" "alu_shift,load_byte")
3754169689Skan   (set_attr "pool_range" "*,1020")]
3755169689Skan)
3756169689Skan
375790075Sobrien(define_expand "extendhisi2_mem"
375890075Sobrien  [(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" "")))
375990075Sobrien   (set (match_dup 3)
376090075Sobrien	(zero_extend:SI (match_dup 7)))
376190075Sobrien   (set (match_dup 6) (ashift:SI (match_dup 4) (const_int 24)))
376290075Sobrien   (set (match_operand:SI 0 "" "")
376390075Sobrien	(ior:SI (ashiftrt:SI (match_dup 6) (const_int 16)) (match_dup 5)))]
376490075Sobrien  "TARGET_ARM"
376590075Sobrien  "
376690075Sobrien  {
376790075Sobrien    rtx mem1, mem2;
376890075Sobrien    rtx addr = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
376990075Sobrien
3770169689Skan    mem1 = change_address (operands[1], QImode, addr);
3771169689Skan    mem2 = change_address (operands[1], QImode, plus_constant (addr, 1));
377290075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
377390075Sobrien    operands[1] = mem1;
377490075Sobrien    operands[2] = gen_reg_rtx (SImode);
377590075Sobrien    operands[3] = gen_reg_rtx (SImode);
377690075Sobrien    operands[6] = gen_reg_rtx (SImode);
377790075Sobrien    operands[7] = mem2;
377890075Sobrien
377990075Sobrien    if (BYTES_BIG_ENDIAN)
378090075Sobrien      {
378190075Sobrien	operands[4] = operands[2];
378290075Sobrien	operands[5] = operands[3];
378390075Sobrien      }
378490075Sobrien    else
378590075Sobrien      {
378690075Sobrien	operands[4] = operands[3];
378790075Sobrien	operands[5] = operands[2];
378890075Sobrien      }
378990075Sobrien  }"
379090075Sobrien)
379190075Sobrien
3792169689Skan(define_insn "*arm_extendhisi2"
3793169689Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
3794169689Skan	(sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
3795169689Skan  "TARGET_ARM && arm_arch4 && !arm_arch6"
379690075Sobrien  "ldr%?sh\\t%0, %1"
3797169689Skan  [(set_attr "type" "load_byte")
379890075Sobrien   (set_attr "predicable" "yes")
379990075Sobrien   (set_attr "pool_range" "256")
380090075Sobrien   (set_attr "neg_pool_range" "244")]
380190075Sobrien)
380290075Sobrien
3803169689Skan(define_insn "*arm_extendhisi2_v6"
3804169689Skan  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
3805169689Skan	(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
3806169689Skan  "TARGET_ARM && arm_arch6"
3807169689Skan  "@
3808169689Skan   sxth%?\\t%0, %1
3809169689Skan   ldr%?sh\\t%0, %1"
3810169689Skan  [(set_attr "type" "alu_shift,load_byte")
3811169689Skan   (set_attr "predicable" "yes")
3812169689Skan   (set_attr "pool_range" "*,256")
3813169689Skan   (set_attr "neg_pool_range" "*,244")]
381490075Sobrien)
381590075Sobrien
3816169689Skan(define_insn "*arm_extendhisi2addsi"
3817169689Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
3818169689Skan	(plus:SI (sign_extend:SI (match_operand:HI 1 "s_register_operand" "r"))
3819169689Skan		 (match_operand:SI 2 "s_register_operand" "r")))]
3820169689Skan  "TARGET_ARM && arm_arch6"
3821169689Skan  "sxtah%?\\t%0, %2, %1"
382290075Sobrien)
382390075Sobrien
382490075Sobrien(define_expand "extendqihi2"
382590075Sobrien  [(set (match_dup 2)
382690075Sobrien	(ashift:SI (match_operand:QI 1 "general_operand" "")
382790075Sobrien		   (const_int 24)))
382890075Sobrien   (set (match_operand:HI 0 "s_register_operand" "")
382990075Sobrien	(ashiftrt:SI (match_dup 2)
383090075Sobrien		     (const_int 24)))]
383190075Sobrien  "TARGET_ARM"
383290075Sobrien  "
383390075Sobrien  {
383490075Sobrien    if (arm_arch4 && GET_CODE (operands[1]) == MEM)
383590075Sobrien      {
383690075Sobrien	emit_insn (gen_rtx_SET (VOIDmode,
383790075Sobrien				operands[0],
383890075Sobrien				gen_rtx_SIGN_EXTEND (HImode, operands[1])));
383990075Sobrien	DONE;
384090075Sobrien      }
384190075Sobrien    if (!s_register_operand (operands[1], QImode))
384290075Sobrien      operands[1] = copy_to_mode_reg (QImode, operands[1]);
384390075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
384490075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
384590075Sobrien    operands[2] = gen_reg_rtx (SImode);
384690075Sobrien  }"
384790075Sobrien)
384890075Sobrien
384990075Sobrien(define_insn "*extendqihi_insn"
3850169689Skan  [(set (match_operand:HI 0 "s_register_operand" "=r")
3851169689Skan	(sign_extend:HI (match_operand:QI 1 "memory_operand" "Uq")))]
385290075Sobrien  "TARGET_ARM && arm_arch4"
3853169689Skan  "ldr%?sb\\t%0, %1"
3854169689Skan  [(set_attr "type" "load_byte")
385590075Sobrien   (set_attr "predicable" "yes")
385690075Sobrien   (set_attr "pool_range" "256")
385790075Sobrien   (set_attr "neg_pool_range" "244")]
385890075Sobrien)
385990075Sobrien
386090075Sobrien(define_expand "extendqisi2"
386190075Sobrien  [(set (match_dup 2)
386290075Sobrien	(ashift:SI (match_operand:QI 1 "general_operand" "")
386390075Sobrien		   (const_int 24)))
386490075Sobrien   (set (match_operand:SI 0 "s_register_operand" "")
386590075Sobrien	(ashiftrt:SI (match_dup 2)
386690075Sobrien		     (const_int 24)))]
386790075Sobrien  "TARGET_EITHER"
386890075Sobrien  "
386990075Sobrien  {
3870169689Skan    if ((TARGET_THUMB || arm_arch4) && GET_CODE (operands[1]) == MEM)
387190075Sobrien      {
3872169689Skan        emit_insn (gen_rtx_SET (VOIDmode, operands[0],
387390075Sobrien			        gen_rtx_SIGN_EXTEND (SImode, operands[1])));
387490075Sobrien        DONE;
387590075Sobrien      }
3876169689Skan
387790075Sobrien    if (!s_register_operand (operands[1], QImode))
387890075Sobrien      operands[1] = copy_to_mode_reg (QImode, operands[1]);
3879169689Skan
3880169689Skan    if (arm_arch6)
3881169689Skan      {
3882169689Skan        emit_insn (gen_rtx_SET (VOIDmode, operands[0],
3883169689Skan			        gen_rtx_SIGN_EXTEND (SImode, operands[1])));
3884169689Skan        DONE;
3885169689Skan      }
3886169689Skan
388790075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
388890075Sobrien    operands[2] = gen_reg_rtx (SImode);
388990075Sobrien  }"
389090075Sobrien)
389190075Sobrien
3892169689Skan(define_insn "*arm_extendqisi"
3893169689Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
3894169689Skan	(sign_extend:SI (match_operand:QI 1 "memory_operand" "Uq")))]
3895169689Skan  "TARGET_ARM && arm_arch4 && !arm_arch6"
3896169689Skan  "ldr%?sb\\t%0, %1"
3897169689Skan  [(set_attr "type" "load_byte")
389890075Sobrien   (set_attr "predicable" "yes")
389990075Sobrien   (set_attr "pool_range" "256")
390090075Sobrien   (set_attr "neg_pool_range" "244")]
390190075Sobrien)
390290075Sobrien
3903169689Skan(define_insn "*arm_extendqisi_v6"
3904169689Skan  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
3905169689Skan	(sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,Uq")))]
3906169689Skan  "TARGET_ARM && arm_arch6"
3907169689Skan  "@
3908169689Skan   sxtb%?\\t%0, %1
3909169689Skan   ldr%?sb\\t%0, %1"
3910169689Skan  [(set_attr "type" "alu_shift,load_byte")
3911169689Skan   (set_attr "predicable" "yes")
3912169689Skan   (set_attr "pool_range" "*,256")
3913169689Skan   (set_attr "neg_pool_range" "*,244")]
3914169689Skan)
391590075Sobrien
3916169689Skan(define_insn "*arm_extendqisi2addsi"
3917169689Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
3918169689Skan	(plus:SI (sign_extend:SI (match_operand:QI 1 "s_register_operand" "r"))
3919169689Skan		 (match_operand:SI 2 "s_register_operand" "r")))]
3920169689Skan  "TARGET_ARM && arm_arch6"
3921169689Skan  "sxtab%?\\t%0, %2, %1"
3922169689Skan  [(set_attr "type" "alu_shift")
3923169689Skan   (set_attr "predicable" "yes")]
392490075Sobrien)
392590075Sobrien
3926169689Skan(define_insn "*thumb_extendqisi2"
3927169689Skan  [(set (match_operand:SI 0 "register_operand" "=l,l")
3928169689Skan	(sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))]
3929169689Skan  "TARGET_THUMB && !arm_arch6"
393090075Sobrien  "*
393190075Sobrien  {
393290075Sobrien    rtx ops[3];
393390075Sobrien    rtx mem = XEXP (operands[1], 0);
393490075Sobrien    
393590075Sobrien    if (GET_CODE (mem) == CONST)
393690075Sobrien      mem = XEXP (mem, 0);
393790075Sobrien    
393890075Sobrien    if (GET_CODE (mem) == LABEL_REF)
393990075Sobrien      return \"ldr\\t%0, %1\";
394090075Sobrien
394190075Sobrien    if (GET_CODE (mem) == PLUS
394290075Sobrien        && GET_CODE (XEXP (mem, 0)) == LABEL_REF)
394390075Sobrien      return \"ldr\\t%0, %1\";
394490075Sobrien      
394590075Sobrien    if (which_alternative == 0)
394690075Sobrien      return \"ldrsb\\t%0, %1\";
394790075Sobrien      
394890075Sobrien    ops[0] = operands[0];
394990075Sobrien    
395090075Sobrien    if (GET_CODE (mem) == PLUS)
395190075Sobrien      {
395290075Sobrien        rtx a = XEXP (mem, 0);
395390075Sobrien	rtx b = XEXP (mem, 1);
395490075Sobrien	
395590075Sobrien        ops[1] = a;
395690075Sobrien        ops[2] = b;
395790075Sobrien
395890075Sobrien        if (GET_CODE (a) == REG)
395990075Sobrien	  {
396090075Sobrien	    if (GET_CODE (b) == REG)
396190075Sobrien              output_asm_insn (\"ldrsb\\t%0, [%1, %2]\", ops);
396290075Sobrien            else if (REGNO (a) == REGNO (ops[0]))
396390075Sobrien	      {
396490075Sobrien                output_asm_insn (\"ldrb\\t%0, [%1, %2]\", ops);
396590075Sobrien		output_asm_insn (\"lsl\\t%0, %0, #24\", ops);
396690075Sobrien		output_asm_insn (\"asr\\t%0, %0, #24\", ops);
396790075Sobrien	      }
396890075Sobrien	    else
396990075Sobrien              output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops);
397090075Sobrien	  }
397190075Sobrien	else
397290075Sobrien          {
3973169689Skan	    gcc_assert (GET_CODE (b) == REG);
397490075Sobrien            if (REGNO (b) == REGNO (ops[0]))
397590075Sobrien	      {
397690075Sobrien                output_asm_insn (\"ldrb\\t%0, [%2, %1]\", ops);
397790075Sobrien		output_asm_insn (\"lsl\\t%0, %0, #24\", ops);
397890075Sobrien		output_asm_insn (\"asr\\t%0, %0, #24\", ops);
397990075Sobrien	      }
398090075Sobrien	    else
398190075Sobrien              output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops);
398290075Sobrien          }
398390075Sobrien      }
398490075Sobrien    else if (GET_CODE (mem) == REG && REGNO (ops[0]) == REGNO (mem))
398590075Sobrien      {
398690075Sobrien        output_asm_insn (\"ldrb\\t%0, [%0, #0]\", ops);
398790075Sobrien	output_asm_insn (\"lsl\\t%0, %0, #24\", ops);
398890075Sobrien	output_asm_insn (\"asr\\t%0, %0, #24\", ops);
398990075Sobrien      }
399090075Sobrien    else
399190075Sobrien      {
399290075Sobrien        ops[1] = mem;
399390075Sobrien        ops[2] = const0_rtx;
399490075Sobrien	
399590075Sobrien        output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops);
399690075Sobrien      }
399790075Sobrien    return \"\";
399890075Sobrien  }"
399990075Sobrien  [(set_attr "length" "2,6")
4000169689Skan   (set_attr "type" "load_byte,load_byte")
400190075Sobrien   (set_attr "pool_range" "32,32")]
400290075Sobrien)
400390075Sobrien
4004169689Skan(define_insn "*thumb_extendqisi2_v6"
4005169689Skan  [(set (match_operand:SI 0 "register_operand" "=l,l,l")
4006169689Skan	(sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "l,V,m")))]
4007169689Skan  "TARGET_THUMB && arm_arch6"
4008169689Skan  "*
4009169689Skan  {
4010169689Skan    rtx ops[3];
4011169689Skan    rtx mem;
4012169689Skan
4013169689Skan    if (which_alternative == 0)
4014169689Skan      return \"sxtb\\t%0, %1\";
4015169689Skan
4016169689Skan    mem = XEXP (operands[1], 0);
4017169689Skan    
4018169689Skan    if (GET_CODE (mem) == CONST)
4019169689Skan      mem = XEXP (mem, 0);
4020169689Skan    
4021169689Skan    if (GET_CODE (mem) == LABEL_REF)
4022169689Skan      return \"ldr\\t%0, %1\";
4023169689Skan
4024169689Skan    if (GET_CODE (mem) == PLUS
4025169689Skan        && GET_CODE (XEXP (mem, 0)) == LABEL_REF)
4026169689Skan      return \"ldr\\t%0, %1\";
4027169689Skan      
4028169689Skan    if (which_alternative == 0)
4029169689Skan      return \"ldrsb\\t%0, %1\";
4030169689Skan      
4031169689Skan    ops[0] = operands[0];
4032169689Skan    
4033169689Skan    if (GET_CODE (mem) == PLUS)
4034169689Skan      {
4035169689Skan        rtx a = XEXP (mem, 0);
4036169689Skan	rtx b = XEXP (mem, 1);
4037169689Skan	
4038169689Skan        ops[1] = a;
4039169689Skan        ops[2] = b;
4040169689Skan
4041169689Skan        if (GET_CODE (a) == REG)
4042169689Skan	  {
4043169689Skan	    if (GET_CODE (b) == REG)
4044169689Skan              output_asm_insn (\"ldrsb\\t%0, [%1, %2]\", ops);
4045169689Skan            else if (REGNO (a) == REGNO (ops[0]))
4046169689Skan	      {
4047169689Skan                output_asm_insn (\"ldrb\\t%0, [%1, %2]\", ops);
4048169689Skan		output_asm_insn (\"sxtb\\t%0, %0\", ops);
4049169689Skan	      }
4050169689Skan	    else
4051169689Skan              output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops);
4052169689Skan	  }
4053169689Skan	else
4054169689Skan          {
4055169689Skan	    gcc_assert (GET_CODE (b) == REG);
4056169689Skan            if (REGNO (b) == REGNO (ops[0]))
4057169689Skan	      {
4058169689Skan                output_asm_insn (\"ldrb\\t%0, [%2, %1]\", ops);
4059169689Skan		output_asm_insn (\"sxtb\\t%0, %0\", ops);
4060169689Skan	      }
4061169689Skan	    else
4062169689Skan              output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops);
4063169689Skan          }
4064169689Skan      }
4065169689Skan    else if (GET_CODE (mem) == REG && REGNO (ops[0]) == REGNO (mem))
4066169689Skan      {
4067169689Skan        output_asm_insn (\"ldrb\\t%0, [%0, #0]\", ops);
4068169689Skan	output_asm_insn (\"sxtb\\t%0, %0\", ops);
4069169689Skan      }
4070169689Skan    else
4071169689Skan      {
4072169689Skan        ops[1] = mem;
4073169689Skan        ops[2] = const0_rtx;
4074169689Skan	
4075169689Skan        output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops);
4076169689Skan      }
4077169689Skan    return \"\";
4078169689Skan  }"
4079169689Skan  [(set_attr "length" "2,2,4")
4080169689Skan   (set_attr "type" "alu_shift,load_byte,load_byte")
4081169689Skan   (set_attr "pool_range" "*,32,32")]
4082169689Skan)
4083169689Skan
4084132718Skan(define_expand "extendsfdf2"
4085132718Skan  [(set (match_operand:DF                  0 "s_register_operand" "")
4086132718Skan	(float_extend:DF (match_operand:SF 1 "s_register_operand"  "")))]
4087169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT"
4088132718Skan  ""
408990075Sobrien)
409090075Sobrien
409190075Sobrien;; Move insns (including loads and stores)
409290075Sobrien
409390075Sobrien;; XXX Just some ideas about movti.
409490075Sobrien;; I don't think these are a good idea on the arm, there just aren't enough
409590075Sobrien;; registers
409690075Sobrien;;(define_expand "loadti"
409790075Sobrien;;  [(set (match_operand:TI 0 "s_register_operand" "")
409890075Sobrien;;	(mem:TI (match_operand:SI 1 "address_operand" "")))]
409990075Sobrien;;  "" "")
410090075Sobrien
410190075Sobrien;;(define_expand "storeti"
410290075Sobrien;;  [(set (mem:TI (match_operand:TI 0 "address_operand" ""))
410390075Sobrien;;	(match_operand:TI 1 "s_register_operand" ""))]
410490075Sobrien;;  "" "")
410590075Sobrien
410690075Sobrien;;(define_expand "movti"
410790075Sobrien;;  [(set (match_operand:TI 0 "general_operand" "")
410890075Sobrien;;	(match_operand:TI 1 "general_operand" ""))]
410990075Sobrien;;  ""
411090075Sobrien;;  "
411190075Sobrien;;{
411290075Sobrien;;  rtx insn;
411390075Sobrien;;
411490075Sobrien;;  if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
411590075Sobrien;;    operands[1] = copy_to_reg (operands[1]);
411690075Sobrien;;  if (GET_CODE (operands[0]) == MEM)
411790075Sobrien;;    insn = gen_storeti (XEXP (operands[0], 0), operands[1]);
411890075Sobrien;;  else if (GET_CODE (operands[1]) == MEM)
411990075Sobrien;;    insn = gen_loadti (operands[0], XEXP (operands[1], 0));
412090075Sobrien;;  else
412190075Sobrien;;    FAIL;
412290075Sobrien;;
412390075Sobrien;;  emit_insn (insn);
412490075Sobrien;;  DONE;
412590075Sobrien;;}")
412690075Sobrien
4127117395Skan;; Recognize garbage generated above.
412890075Sobrien
412990075Sobrien;;(define_insn ""
413090075Sobrien;;  [(set (match_operand:TI 0 "general_operand" "=r,r,r,<,>,m")
413190075Sobrien;;	(match_operand:TI 1 "general_operand" "<,>,m,r,r,r"))]
413290075Sobrien;;  ""
413390075Sobrien;;  "*
413490075Sobrien;;  {
413590075Sobrien;;    register mem = (which_alternative < 3);
413690075Sobrien;;    register const char *template;
413790075Sobrien;;
413890075Sobrien;;    operands[mem] = XEXP (operands[mem], 0);
413990075Sobrien;;    switch (which_alternative)
414090075Sobrien;;      {
414190075Sobrien;;      case 0: template = \"ldmdb\\t%1!, %M0\"; break;
414290075Sobrien;;      case 1: template = \"ldmia\\t%1!, %M0\"; break;
414390075Sobrien;;      case 2: template = \"ldmia\\t%1, %M0\"; break;
414490075Sobrien;;      case 3: template = \"stmdb\\t%0!, %M1\"; break;
414590075Sobrien;;      case 4: template = \"stmia\\t%0!, %M1\"; break;
414690075Sobrien;;      case 5: template = \"stmia\\t%0, %M1\"; break;
414790075Sobrien;;      }
414890075Sobrien;;    output_asm_insn (template, operands);
414990075Sobrien;;    return \"\";
415090075Sobrien;;  }")
415190075Sobrien
415290075Sobrien(define_expand "movdi"
415390075Sobrien  [(set (match_operand:DI 0 "general_operand" "")
415490075Sobrien	(match_operand:DI 1 "general_operand" ""))]
415590075Sobrien  "TARGET_EITHER"
415690075Sobrien  "
4157169689Skan  if (!no_new_pseudos)
415890075Sobrien    {
4159169689Skan      if (GET_CODE (operands[0]) != REG)
4160169689Skan	operands[1] = force_reg (DImode, operands[1]);
416190075Sobrien    }
416290075Sobrien  "
416390075Sobrien)
416490075Sobrien
416590075Sobrien(define_insn "*arm_movdi"
4166169689Skan  [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r, r, r, r, m")
4167169689Skan	(match_operand:DI 1 "di_operand"              "rDa,Db,Dc,mi,r"))]
4168169689Skan  "TARGET_ARM
4169169689Skan   && !(TARGET_HARD_FLOAT && (TARGET_MAVERICK || TARGET_VFP))
4170169689Skan   && !TARGET_IWMMXT
4171169689Skan   && (   register_operand (operands[0], DImode)
4172169689Skan       || register_operand (operands[1], DImode))"
417390075Sobrien  "*
4174169689Skan  switch (which_alternative)
4175169689Skan    {
4176169689Skan    case 0:
4177169689Skan    case 1:
4178169689Skan    case 2:
4179169689Skan      return \"#\";
4180169689Skan    default:
4181169689Skan      return output_move_double (operands);
4182169689Skan    }
418390075Sobrien  "
4184169689Skan  [(set_attr "length" "8,12,16,8,8")
4185169689Skan   (set_attr "type" "*,*,*,load2,store2")
4186169689Skan   (set_attr "pool_range" "*,*,*,1020,*")
4187169689Skan   (set_attr "neg_pool_range" "*,*,*,1008,*")]
418890075Sobrien)
418990075Sobrien
4190169689Skan(define_split
4191169689Skan  [(set (match_operand:ANY64 0 "arm_general_register_operand" "")
4192169689Skan	(match_operand:ANY64 1 "const_double_operand" ""))]
4193169689Skan  "TARGET_ARM
4194169689Skan   && reload_completed
4195169689Skan   && (arm_const_double_inline_cost (operands[1])
4196169689Skan       <= ((optimize_size || arm_ld_sched) ? 3 : 4))"
4197169689Skan  [(const_int 0)]
4198169689Skan  "
4199169689Skan  arm_split_constant (SET, SImode, curr_insn,
4200169689Skan		      INTVAL (gen_lowpart (SImode, operands[1])),
4201169689Skan		      gen_lowpart (SImode, operands[0]), NULL_RTX, 0);
4202169689Skan  arm_split_constant (SET, SImode, curr_insn,
4203169689Skan		      INTVAL (gen_highpart_mode (SImode,
4204169689Skan						 GET_MODE (operands[0]),
4205169689Skan						 operands[1])),
4206169689Skan		      gen_highpart (SImode, operands[0]), NULL_RTX, 0);
4207169689Skan  DONE;
4208169689Skan  "
4209169689Skan)
4210169689Skan
4211169689Skan; If optimizing for size, or if we have load delay slots, then 
4212169689Skan; we want to split the constant into two separate operations. 
4213169689Skan; In both cases this may split a trivial part into a single data op
4214169689Skan; leaving a single complex constant to load.  We can also get longer
4215169689Skan; offsets in a LDR which means we get better chances of sharing the pool
4216169689Skan; entries.  Finally, we can normally do a better job of scheduling
4217169689Skan; LDR instructions than we can with LDM.
4218169689Skan; This pattern will only match if the one above did not.
4219169689Skan(define_split
4220169689Skan  [(set (match_operand:ANY64 0 "arm_general_register_operand" "")
4221169689Skan	(match_operand:ANY64 1 "const_double_operand" ""))]
4222169689Skan  "TARGET_ARM && reload_completed
4223169689Skan   && arm_const_double_by_parts (operands[1])"
4224169689Skan  [(set (match_dup 0) (match_dup 1))
4225169689Skan   (set (match_dup 2) (match_dup 3))]
4226169689Skan  "
4227169689Skan  operands[2] = gen_highpart (SImode, operands[0]);
4228169689Skan  operands[3] = gen_highpart_mode (SImode, GET_MODE (operands[0]),
4229169689Skan				   operands[1]);
4230169689Skan  operands[0] = gen_lowpart (SImode, operands[0]);
4231169689Skan  operands[1] = gen_lowpart (SImode, operands[1]);
4232169689Skan  "
4233169689Skan)
4234169689Skan
4235169689Skan(define_split
4236169689Skan  [(set (match_operand:ANY64 0 "arm_general_register_operand" "")
4237169689Skan	(match_operand:ANY64 1 "arm_general_register_operand" ""))]
4238169689Skan  "TARGET_EITHER && reload_completed"
4239169689Skan  [(set (match_dup 0) (match_dup 1))
4240169689Skan   (set (match_dup 2) (match_dup 3))]
4241169689Skan  "
4242169689Skan  operands[2] = gen_highpart (SImode, operands[0]);
4243169689Skan  operands[3] = gen_highpart (SImode, operands[1]);
4244169689Skan  operands[0] = gen_lowpart (SImode, operands[0]);
4245169689Skan  operands[1] = gen_lowpart (SImode, operands[1]);
4246169689Skan
4247169689Skan  /* Handle a partial overlap.  */
4248169689Skan  if (rtx_equal_p (operands[0], operands[3]))
4249169689Skan    {
4250169689Skan      rtx tmp0 = operands[0];
4251169689Skan      rtx tmp1 = operands[1];
4252169689Skan
4253169689Skan      operands[0] = operands[2];
4254169689Skan      operands[1] = operands[3];
4255169689Skan      operands[2] = tmp0;
4256169689Skan      operands[3] = tmp1;
4257169689Skan    }
4258169689Skan  "
4259169689Skan)
4260169689Skan
4261169689Skan;; We can't actually do base+index doubleword loads if the index and
4262169689Skan;; destination overlap.  Split here so that we at least have chance to
4263169689Skan;; schedule.
4264169689Skan(define_split
4265169689Skan  [(set (match_operand:DI 0 "s_register_operand" "")
4266169689Skan	(mem:DI (plus:SI (match_operand:SI 1 "s_register_operand" "")
4267169689Skan			 (match_operand:SI 2 "s_register_operand" ""))))]
4268169689Skan  "TARGET_LDRD
4269169689Skan  && reg_overlap_mentioned_p (operands[0], operands[1])
4270169689Skan  && reg_overlap_mentioned_p (operands[0], operands[2])"
4271169689Skan  [(set (match_dup 4)
4272169689Skan	(plus:SI (match_dup 1)
4273169689Skan		 (match_dup 2)))
4274169689Skan   (set (match_dup 0)
4275169689Skan	(mem:DI (match_dup 4)))]
4276169689Skan  "
4277169689Skan  operands[4] = gen_rtx_REG (SImode, REGNO(operands[0]));
4278169689Skan  "
4279169689Skan)
4280169689Skan
428190075Sobrien;;; ??? This should have alternatives for constants.
428290075Sobrien;;; ??? This was originally identical to the movdf_insn pattern.
428390075Sobrien;;; ??? The 'i' constraint looks funny, but it should always be replaced by
428490075Sobrien;;; thumb_reorg with a memory reference.
428590075Sobrien(define_insn "*thumb_movdi_insn"
428690075Sobrien  [(set (match_operand:DI 0 "nonimmediate_operand" "=l,l,l,l,>,l, m,*r")
428790075Sobrien	(match_operand:DI 1 "general_operand"      "l, I,J,>,l,mi,l,*r"))]
428890075Sobrien  "TARGET_THUMB
4289169689Skan   && !(TARGET_HARD_FLOAT && TARGET_MAVERICK)
429090075Sobrien   && (   register_operand (operands[0], DImode)
429190075Sobrien       || register_operand (operands[1], DImode))"
429290075Sobrien  "*
429390075Sobrien  {
429490075Sobrien  switch (which_alternative)
429590075Sobrien    {
429690075Sobrien    default:
429790075Sobrien    case 0:
429890075Sobrien      if (REGNO (operands[1]) == REGNO (operands[0]) + 1)
429990075Sobrien	return \"add\\t%0,  %1,  #0\;add\\t%H0, %H1, #0\";
430090075Sobrien      return   \"add\\t%H0, %H1, #0\;add\\t%0,  %1,  #0\";
430190075Sobrien    case 1:
430290075Sobrien      return \"mov\\t%Q0, %1\;mov\\t%R0, #0\";
430390075Sobrien    case 2:
430490075Sobrien      operands[1] = GEN_INT (- INTVAL (operands[1]));
430590075Sobrien      return \"mov\\t%Q0, %1\;neg\\t%Q0, %Q0\;asr\\t%R0, %Q0, #31\";
430690075Sobrien    case 3:
430790075Sobrien      return \"ldmia\\t%1, {%0, %H0}\";
430890075Sobrien    case 4:
430990075Sobrien      return \"stmia\\t%0, {%1, %H1}\";
431090075Sobrien    case 5:
431190075Sobrien      return thumb_load_double_from_address (operands);
431290075Sobrien    case 6:
4313169689Skan      operands[2] = gen_rtx_MEM (SImode,
431490075Sobrien			     plus_constant (XEXP (operands[0], 0), 4));
431590075Sobrien      output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands);
431690075Sobrien      return \"\";
431790075Sobrien    case 7:
431890075Sobrien      if (REGNO (operands[1]) == REGNO (operands[0]) + 1)
431990075Sobrien	return \"mov\\t%0, %1\;mov\\t%H0, %H1\";
432090075Sobrien      return \"mov\\t%H0, %H1\;mov\\t%0, %1\";
432190075Sobrien    }
432290075Sobrien  }"
432390075Sobrien  [(set_attr "length" "4,4,6,2,2,6,4,4")
4324169689Skan   (set_attr "type" "*,*,*,load2,store2,load2,store2,*")
432590075Sobrien   (set_attr "pool_range" "*,*,*,*,*,1020,*,*")]
432690075Sobrien)
432790075Sobrien
432890075Sobrien(define_expand "movsi"
432990075Sobrien  [(set (match_operand:SI 0 "general_operand" "")
433090075Sobrien        (match_operand:SI 1 "general_operand" ""))]
433190075Sobrien  "TARGET_EITHER"
433290075Sobrien  "
433390075Sobrien  if (TARGET_ARM)
433490075Sobrien    {
4335132718Skan      /* Everything except mem = const or mem = mem can be done easily.  */
433690075Sobrien      if (GET_CODE (operands[0]) == MEM)
433790075Sobrien        operands[1] = force_reg (SImode, operands[1]);
4338169689Skan      if (arm_general_register_operand (operands[0], SImode)
4339169689Skan	  && GET_CODE (operands[1]) == CONST_INT
434090075Sobrien          && !(const_ok_for_arm (INTVAL (operands[1]))
434190075Sobrien               || const_ok_for_arm (~INTVAL (operands[1]))))
434290075Sobrien        {
4343169689Skan           arm_split_constant (SET, SImode, NULL_RTX,
4344169689Skan	                       INTVAL (operands[1]), operands[0], NULL_RTX,
4345169689Skan			       optimize && !no_new_pseudos);
434690075Sobrien          DONE;
434790075Sobrien        }
434890075Sobrien    }
4349132718Skan  else /* TARGET_THUMB....  */
435090075Sobrien    {
435190075Sobrien      if (!no_new_pseudos)
435290075Sobrien        {
435390075Sobrien          if (GET_CODE (operands[0]) != REG)
435490075Sobrien	    operands[1] = force_reg (SImode, operands[1]);
435590075Sobrien        }
435690075Sobrien    }
4357169689Skan
4358169689Skan  /* Recognize the case where operand[1] is a reference to thread-local
4359169689Skan     data and load its address to a register.  */
4360169689Skan  if (arm_tls_referenced_p (operands[1]))
4361169689Skan    {
4362169689Skan      rtx tmp = operands[1];
4363169689Skan      rtx addend = NULL;
4364169689Skan
4365169689Skan      if (GET_CODE (tmp) == CONST && GET_CODE (XEXP (tmp, 0)) == PLUS)
4366169689Skan        {
4367169689Skan          addend = XEXP (XEXP (tmp, 0), 1);
4368169689Skan          tmp = XEXP (XEXP (tmp, 0), 0);
4369169689Skan        }
4370169689Skan
4371169689Skan      gcc_assert (GET_CODE (tmp) == SYMBOL_REF);
4372169689Skan      gcc_assert (SYMBOL_REF_TLS_MODEL (tmp) != 0);
4373169689Skan
4374169689Skan      tmp = legitimize_tls_address (tmp, no_new_pseudos ? operands[0] : 0);
4375169689Skan      if (addend)
4376169689Skan        {
4377169689Skan          tmp = gen_rtx_PLUS (SImode, tmp, addend);
4378169689Skan          tmp = force_operand (tmp, operands[0]);
4379169689Skan        }
4380169689Skan      operands[1] = tmp;
4381169689Skan    }
4382169689Skan  else if (flag_pic
4383169689Skan	   && (CONSTANT_P (operands[1])
4384169689Skan	       || symbol_mentioned_p (operands[1])
4385169689Skan	       || label_mentioned_p (operands[1])))
4386169689Skan      operands[1] = legitimize_pic_address (operands[1], SImode,
4387169689Skan					    (no_new_pseudos ? operands[0] : 0));
438890075Sobrien  "
438990075Sobrien)
439090075Sobrien
439190075Sobrien(define_insn "*arm_movsi_insn"
439290075Sobrien  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r, m")
439390075Sobrien	(match_operand:SI 1 "general_operand"      "rI,K,mi,r"))]
4394132718Skan  "TARGET_ARM && ! TARGET_IWMMXT
4395169689Skan   && !(TARGET_HARD_FLOAT && TARGET_VFP)
439690075Sobrien   && (   register_operand (operands[0], SImode)
439790075Sobrien       || register_operand (operands[1], SImode))"
439890075Sobrien  "@
439990075Sobrien   mov%?\\t%0, %1
440090075Sobrien   mvn%?\\t%0, #%B1
440190075Sobrien   ldr%?\\t%0, %1
440290075Sobrien   str%?\\t%1, %0"
4403169689Skan  [(set_attr "type" "*,*,load1,store1")
440490075Sobrien   (set_attr "predicable" "yes")
440590075Sobrien   (set_attr "pool_range" "*,*,4096,*")
440690075Sobrien   (set_attr "neg_pool_range" "*,*,4084,*")]
440790075Sobrien)
440890075Sobrien
440990075Sobrien(define_split
4410169689Skan  [(set (match_operand:SI 0 "arm_general_register_operand" "")
441190075Sobrien	(match_operand:SI 1 "const_int_operand" ""))]
441290075Sobrien  "TARGET_ARM
441390075Sobrien  && (!(const_ok_for_arm (INTVAL (operands[1]))
441490075Sobrien        || const_ok_for_arm (~INTVAL (operands[1]))))"
441590075Sobrien  [(clobber (const_int 0))]
441690075Sobrien  "
4417169689Skan  arm_split_constant (SET, SImode, NULL_RTX, 
4418169689Skan                      INTVAL (operands[1]), operands[0], NULL_RTX, 0);
441990075Sobrien  DONE;
442090075Sobrien  "
442190075Sobrien)
442290075Sobrien
442390075Sobrien(define_insn "*thumb_movsi_insn"
442490075Sobrien  [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l, m,*lh")
442590075Sobrien	(match_operand:SI 1 "general_operand"      "l, I,J,K,>,l,mi,l,*lh"))]
442690075Sobrien  "TARGET_THUMB
442790075Sobrien   && (   register_operand (operands[0], SImode) 
442890075Sobrien       || register_operand (operands[1], SImode))"
442990075Sobrien  "@
443090075Sobrien   mov	%0, %1
443190075Sobrien   mov	%0, %1
443290075Sobrien   #
443390075Sobrien   #
443490075Sobrien   ldmia\\t%1, {%0}
443590075Sobrien   stmia\\t%0, {%1}
443690075Sobrien   ldr\\t%0, %1
443790075Sobrien   str\\t%1, %0
443890075Sobrien   mov\\t%0, %1"
443990075Sobrien  [(set_attr "length" "2,2,4,4,2,2,2,2,2")
4440169689Skan   (set_attr "type" "*,*,*,*,load1,store1,load1,store1,*")
444190075Sobrien   (set_attr "pool_range" "*,*,*,*,*,*,1020,*,*")]
444290075Sobrien)
444390075Sobrien
444490075Sobrien(define_split 
444590075Sobrien  [(set (match_operand:SI 0 "register_operand" "")
444690075Sobrien	(match_operand:SI 1 "const_int_operand" ""))]
4447169689Skan  "TARGET_THUMB && satisfies_constraint_J (operands[1])"
444890075Sobrien  [(set (match_dup 0) (match_dup 1))
444990075Sobrien   (set (match_dup 0) (neg:SI (match_dup 0)))]
445090075Sobrien  "operands[1] = GEN_INT (- INTVAL (operands[1]));"
445190075Sobrien)
445290075Sobrien
445390075Sobrien(define_split 
445490075Sobrien  [(set (match_operand:SI 0 "register_operand" "")
445590075Sobrien	(match_operand:SI 1 "const_int_operand" ""))]
4456169689Skan  "TARGET_THUMB && satisfies_constraint_K (operands[1])"
445790075Sobrien  [(set (match_dup 0) (match_dup 1))
445890075Sobrien   (set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))]
445990075Sobrien  "
446090075Sobrien  {
446190075Sobrien    unsigned HOST_WIDE_INT val = INTVAL (operands[1]);
446290075Sobrien    unsigned HOST_WIDE_INT mask = 0xff;
446390075Sobrien    int i;
446490075Sobrien    
446590075Sobrien    for (i = 0; i < 25; i++)
446690075Sobrien      if ((val & (mask << i)) == val)
446790075Sobrien        break;
446890075Sobrien
4469117395Skan    /* Shouldn't happen, but we don't want to split if the shift is zero.  */
447090075Sobrien    if (i == 0)
447190075Sobrien      FAIL;
447290075Sobrien
447390075Sobrien    operands[1] = GEN_INT (val >> i);
447490075Sobrien    operands[2] = GEN_INT (i);
447590075Sobrien  }"
447690075Sobrien)
447790075Sobrien
447890075Sobrien;; When generating pic, we need to load the symbol offset into a register.
447990075Sobrien;; So that the optimizer does not confuse this with a normal symbol load
448090075Sobrien;; we use an unspec.  The offset will be loaded from a constant pool entry,
448190075Sobrien;; since that is the only type of relocation we can use.
448290075Sobrien
448390075Sobrien;; The rather odd constraints on the following are to force reload to leave
448490075Sobrien;; the insn alone, and to force the minipool generation pass to then move
448590075Sobrien;; the GOT symbol to memory.
448690075Sobrien
448790075Sobrien(define_insn "pic_load_addr_arm"
448890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
448990075Sobrien	(unspec:SI [(match_operand:SI 1 "" "mX")] UNSPEC_PIC_SYM))]
449090075Sobrien  "TARGET_ARM && flag_pic"
449190075Sobrien  "ldr%?\\t%0, %1"
4492169689Skan  [(set_attr "type" "load1")
449390075Sobrien   (set (attr "pool_range")     (const_int 4096))
449490075Sobrien   (set (attr "neg_pool_range") (const_int 4084))]
449590075Sobrien)
449690075Sobrien
449790075Sobrien(define_insn "pic_load_addr_thumb"
449890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=l")
449990075Sobrien	(unspec:SI [(match_operand:SI 1 "" "mX")] UNSPEC_PIC_SYM))]
450090075Sobrien  "TARGET_THUMB && flag_pic"
450190075Sobrien  "ldr\\t%0, %1"
4502169689Skan  [(set_attr "type" "load1")
450390075Sobrien   (set (attr "pool_range") (const_int 1024))]
450490075Sobrien)
450590075Sobrien
450690075Sobrien;; This variant is used for AOF assembly, since it needs to mention the
450790075Sobrien;; pic register in the rtl.
450890075Sobrien(define_expand "pic_load_addr_based"
4509132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
451090075Sobrien	(unspec:SI [(match_operand 1 "" "") (match_dup 2)] UNSPEC_PIC_SYM))]
451190075Sobrien  "TARGET_ARM && flag_pic"
4512169689Skan  "operands[2] = cfun->machine->pic_reg;"
451390075Sobrien)
451490075Sobrien
451590075Sobrien(define_insn "*pic_load_addr_based_insn"
451690075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
451790075Sobrien	(unspec:SI [(match_operand 1 "" "")
451890075Sobrien		    (match_operand 2 "s_register_operand" "r")]
451990075Sobrien		   UNSPEC_PIC_SYM))]
4520169689Skan  "TARGET_EITHER && flag_pic && operands[2] == cfun->machine->pic_reg"
452190075Sobrien  "*
452290075Sobrien#ifdef AOF_ASSEMBLER
452390075Sobrien  operands[1] = aof_pic_entry (operands[1]);
452490075Sobrien#endif
452590075Sobrien  output_asm_insn (\"ldr%?\\t%0, %a1\", operands);
452690075Sobrien  return \"\";
452790075Sobrien  "
4528169689Skan  [(set_attr "type" "load1")
452990075Sobrien   (set (attr "pool_range")
453090075Sobrien	(if_then_else (eq_attr "is_thumb" "yes")
453190075Sobrien		      (const_int 1024)
453290075Sobrien		      (const_int 4096)))
453390075Sobrien   (set (attr "neg_pool_range")
453490075Sobrien	(if_then_else (eq_attr "is_thumb" "yes")
453590075Sobrien		      (const_int 0)
453690075Sobrien		      (const_int 4084)))]
453790075Sobrien)
453890075Sobrien
453990075Sobrien(define_insn "pic_add_dot_plus_four"
4540169689Skan  [(set (match_operand:SI 0 "register_operand" "=r")
4541169689Skan	(unspec:SI [(plus:SI (match_operand:SI 1 "register_operand" "0")
4542117395Skan			     (const (plus:SI (pc) (const_int 4))))]
4543117395Skan		   UNSPEC_PIC_BASE))
4544169689Skan   (use (match_operand 2 "" ""))]
4545169689Skan  "TARGET_THUMB"
454690075Sobrien  "*
4547169689Skan  (*targetm.asm_out.internal_label) (asm_out_file, \"LPIC\",
4548169689Skan				     INTVAL (operands[2]));
454990075Sobrien  return \"add\\t%0, %|pc\";
455090075Sobrien  "
455190075Sobrien  [(set_attr "length" "2")]
455290075Sobrien)
455390075Sobrien
455490075Sobrien(define_insn "pic_add_dot_plus_eight"
4555169689Skan  [(set (match_operand:SI 0 "register_operand" "=r")
4556169689Skan	(unspec:SI [(plus:SI (match_operand:SI 1 "register_operand" "r")
4557117395Skan			     (const (plus:SI (pc) (const_int 8))))]
4558117395Skan		   UNSPEC_PIC_BASE))
4559169689Skan   (use (match_operand 2 "" ""))]
4560169689Skan  "TARGET_ARM"
456190075Sobrien  "*
4562169689Skan    (*targetm.asm_out.internal_label) (asm_out_file, \"LPIC\",
4563169689Skan				       INTVAL (operands[2]));
4564169689Skan    return \"add%?\\t%0, %|pc, %1\";
456590075Sobrien  "
456690075Sobrien  [(set_attr "predicable" "yes")]
456790075Sobrien)
456890075Sobrien
4569169689Skan(define_insn "tls_load_dot_plus_eight"
4570169689Skan  [(set (match_operand:SI 0 "register_operand" "+r")
4571169689Skan	(mem:SI (unspec:SI [(plus:SI (match_operand:SI 1 "register_operand" "r")
4572169689Skan				     (const (plus:SI (pc) (const_int 8))))]
4573169689Skan			   UNSPEC_PIC_BASE)))
4574169689Skan   (use (match_operand 2 "" ""))]
4575169689Skan  "TARGET_ARM"
4576169689Skan  "*
4577169689Skan    (*targetm.asm_out.internal_label) (asm_out_file, \"LPIC\",
4578169689Skan				       INTVAL (operands[2]));
4579169689Skan    return \"ldr%?\\t%0, [%|pc, %1]\t\t@ tls_load_dot_plus_eight\";
4580169689Skan  "
4581169689Skan  [(set_attr "predicable" "yes")]
4582169689Skan)
4583169689Skan
4584169689Skan;; PIC references to local variables can generate pic_add_dot_plus_eight
4585169689Skan;; followed by a load.  These sequences can be crunched down to
4586169689Skan;; tls_load_dot_plus_eight by a peephole.
4587169689Skan
4588169689Skan(define_peephole2
4589169689Skan  [(parallel [(set (match_operand:SI 0 "register_operand" "")
4590169689Skan		   (unspec:SI [(plus:SI (match_operand:SI 3 "register_operand" "")
4591169689Skan			     	 	(const (plus:SI (pc) (const_int 8))))]
4592169689Skan			      UNSPEC_PIC_BASE))
4593169689Skan   	      (use (label_ref (match_operand 1 "" "")))])
4594169689Skan   (set (match_operand:SI 2 "register_operand" "") (mem:SI (match_dup 0)))]
4595169689Skan  "TARGET_ARM && peep2_reg_dead_p (2, operands[0])"
4596169689Skan  [(parallel [(set (match_dup 2)
4597169689Skan		   (mem:SI (unspec:SI [(plus:SI (match_dup 3)
4598169689Skan						(const (plus:SI (pc) (const_int 8))))]
4599169689Skan				      UNSPEC_PIC_BASE)))
4600169689Skan   	      (use (label_ref (match_dup 1)))])]
4601169689Skan  ""
4602169689Skan)
4603169689Skan
460490075Sobrien(define_expand "builtin_setjmp_receiver"
460590075Sobrien  [(label_ref (match_operand 0 "" ""))]
460690075Sobrien  "flag_pic"
460790075Sobrien  "
460890075Sobrien{
4609169689Skan  /* r3 is clobbered by set/longjmp, so we can use it as a scratch
4610169689Skan     register.  */
4611169689Skan  if (arm_pic_register != INVALID_REGNUM)
4612169689Skan    arm_load_pic_register (1UL << 3);
461390075Sobrien  DONE;
461490075Sobrien}")
461590075Sobrien
461690075Sobrien;; If copying one reg to another we can set the condition codes according to
461790075Sobrien;; its value.  Such a move is common after a return from subroutine and the
461890075Sobrien;; result is being tested against zero.
461990075Sobrien
462090075Sobrien(define_insn "*movsi_compare0"
462190075Sobrien  [(set (reg:CC CC_REGNUM)
462290075Sobrien	(compare:CC (match_operand:SI 1 "s_register_operand" "0,r")
462390075Sobrien		    (const_int 0)))
462490075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r,r")
462590075Sobrien	(match_dup 1))]
462690075Sobrien  "TARGET_ARM"
462790075Sobrien  "@
462890075Sobrien   cmp%?\\t%0, #0
462990075Sobrien   sub%?s\\t%0, %1, #0"
463090075Sobrien  [(set_attr "conds" "set")]
463190075Sobrien)
463290075Sobrien
463390075Sobrien;; Subroutine to store a half word from a register into memory.
463490075Sobrien;; Operand 0 is the source register (HImode)
463590075Sobrien;; Operand 1 is the destination address in a register (SImode)
463690075Sobrien
463790075Sobrien;; In both this routine and the next, we must be careful not to spill
463890075Sobrien;; a memory address of reg+large_const into a separate PLUS insn, since this
463990075Sobrien;; can generate unrecognizable rtl.
464090075Sobrien
464190075Sobrien(define_expand "storehi"
464290075Sobrien  [;; store the low byte
464390075Sobrien   (set (match_operand 1 "" "") (match_dup 3))
464490075Sobrien   ;; extract the high byte
464590075Sobrien   (set (match_dup 2)
464690075Sobrien	(ashiftrt:SI (match_operand 0 "" "") (const_int 8)))
464790075Sobrien   ;; store the high byte
4648132718Skan   (set (match_dup 4) (match_dup 5))]
464990075Sobrien  "TARGET_ARM"
465090075Sobrien  "
465190075Sobrien  {
465290075Sobrien    rtx op1 = operands[1];
465390075Sobrien    rtx addr = XEXP (op1, 0);
465490075Sobrien    enum rtx_code code = GET_CODE (addr);
465590075Sobrien
465690075Sobrien    if ((code == PLUS && GET_CODE (XEXP (addr, 1)) != CONST_INT)
465790075Sobrien	|| code == MINUS)
465890075Sobrien      op1 = replace_equiv_address (operands[1], force_reg (SImode, addr));
465990075Sobrien
466090075Sobrien    operands[4] = adjust_address (op1, QImode, 1);
466190075Sobrien    operands[1] = adjust_address (operands[1], QImode, 0);
466290075Sobrien    operands[3] = gen_lowpart (QImode, operands[0]);
466390075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
4664132718Skan    operands[2] = gen_reg_rtx (SImode);
4665132718Skan    operands[5] = gen_lowpart (QImode, operands[2]);
466690075Sobrien  }"
466790075Sobrien)
466890075Sobrien
466990075Sobrien(define_expand "storehi_bigend"
467090075Sobrien  [(set (match_dup 4) (match_dup 3))
467190075Sobrien   (set (match_dup 2)
467290075Sobrien	(ashiftrt:SI (match_operand 0 "" "") (const_int 8)))
4673132718Skan   (set (match_operand 1 "" "")	(match_dup 5))]
467490075Sobrien  "TARGET_ARM"
467590075Sobrien  "
467690075Sobrien  {
467790075Sobrien    rtx op1 = operands[1];
467890075Sobrien    rtx addr = XEXP (op1, 0);
467990075Sobrien    enum rtx_code code = GET_CODE (addr);
468090075Sobrien
468190075Sobrien    if ((code == PLUS && GET_CODE (XEXP (addr, 1)) != CONST_INT)
468290075Sobrien	|| code == MINUS)
468390075Sobrien      op1 = replace_equiv_address (op1, force_reg (SImode, addr));
468490075Sobrien
468590075Sobrien    operands[4] = adjust_address (op1, QImode, 1);
468690075Sobrien    operands[1] = adjust_address (operands[1], QImode, 0);
468790075Sobrien    operands[3] = gen_lowpart (QImode, operands[0]);
468890075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
468990075Sobrien    operands[2] = gen_reg_rtx (SImode);
4690132718Skan    operands[5] = gen_lowpart (QImode, operands[2]);
469190075Sobrien  }"
469290075Sobrien)
469390075Sobrien
469490075Sobrien;; Subroutine to store a half word integer constant into memory.
469590075Sobrien(define_expand "storeinthi"
469690075Sobrien  [(set (match_operand 0 "" "")
4697132718Skan	(match_operand 1 "" ""))
4698102780Skan   (set (match_dup 3) (match_dup 2))]
469990075Sobrien  "TARGET_ARM"
470090075Sobrien  "
470190075Sobrien  {
470290075Sobrien    HOST_WIDE_INT value = INTVAL (operands[1]);
470390075Sobrien    rtx addr = XEXP (operands[0], 0);
470490075Sobrien    rtx op0 = operands[0];
470590075Sobrien    enum rtx_code code = GET_CODE (addr);
470690075Sobrien
470790075Sobrien    if ((code == PLUS && GET_CODE (XEXP (addr, 1)) != CONST_INT)
470890075Sobrien	|| code == MINUS)
470990075Sobrien      op0 = replace_equiv_address (op0, force_reg (SImode, addr));
471090075Sobrien
471190075Sobrien    operands[1] = gen_reg_rtx (SImode);
471290075Sobrien    if (BYTES_BIG_ENDIAN)
471390075Sobrien      {
471490075Sobrien	emit_insn (gen_movsi (operands[1], GEN_INT ((value >> 8) & 255)));
471590075Sobrien	if ((value & 255) == ((value >> 8) & 255))
471690075Sobrien	  operands[2] = operands[1];
471790075Sobrien	else
471890075Sobrien	  {
471990075Sobrien	    operands[2] = gen_reg_rtx (SImode);
472090075Sobrien	    emit_insn (gen_movsi (operands[2], GEN_INT (value & 255)));
472190075Sobrien	  }
472290075Sobrien      }
472390075Sobrien    else
472490075Sobrien      {
472590075Sobrien	emit_insn (gen_movsi (operands[1], GEN_INT (value & 255)));
472690075Sobrien	if ((value & 255) == ((value >> 8) & 255))
472790075Sobrien	  operands[2] = operands[1];
472890075Sobrien	else
472990075Sobrien	  {
473090075Sobrien	    operands[2] = gen_reg_rtx (SImode);
473190075Sobrien	    emit_insn (gen_movsi (operands[2], GEN_INT ((value >> 8) & 255)));
473290075Sobrien	  }
473390075Sobrien      }
473490075Sobrien
473590075Sobrien    operands[3] = adjust_address (op0, QImode, 1);
473690075Sobrien    operands[0] = adjust_address (operands[0], QImode, 0);
4737102780Skan    operands[2] = gen_lowpart (QImode, operands[2]);
4738132718Skan    operands[1] = gen_lowpart (QImode, operands[1]);
473990075Sobrien  }"
474090075Sobrien)
474190075Sobrien
474290075Sobrien(define_expand "storehi_single_op"
474390075Sobrien  [(set (match_operand:HI 0 "memory_operand" "")
474490075Sobrien	(match_operand:HI 1 "general_operand" ""))]
474590075Sobrien  "TARGET_ARM && arm_arch4"
474690075Sobrien  "
474790075Sobrien  if (!s_register_operand (operands[1], HImode))
474890075Sobrien    operands[1] = copy_to_mode_reg (HImode, operands[1]);
474990075Sobrien  "
475090075Sobrien)
475190075Sobrien
475290075Sobrien(define_expand "movhi"
475390075Sobrien  [(set (match_operand:HI 0 "general_operand" "")
475490075Sobrien	(match_operand:HI 1 "general_operand" ""))]
475590075Sobrien  "TARGET_EITHER"
475690075Sobrien  "
475790075Sobrien  if (TARGET_ARM)
475890075Sobrien    {
475990075Sobrien      if (!no_new_pseudos)
476090075Sobrien        {
476190075Sobrien          if (GET_CODE (operands[0]) == MEM)
476290075Sobrien	    {
476390075Sobrien	      if (arm_arch4)
476490075Sobrien	        {
476590075Sobrien	          emit_insn (gen_storehi_single_op (operands[0], operands[1]));
476690075Sobrien	          DONE;
476790075Sobrien	        }
476890075Sobrien	      if (GET_CODE (operands[1]) == CONST_INT)
476990075Sobrien	        emit_insn (gen_storeinthi (operands[0], operands[1]));
477090075Sobrien	      else
477190075Sobrien	        {
477290075Sobrien	          if (GET_CODE (operands[1]) == MEM)
477390075Sobrien		    operands[1] = force_reg (HImode, operands[1]);
477490075Sobrien	          if (BYTES_BIG_ENDIAN)
477590075Sobrien		    emit_insn (gen_storehi_bigend (operands[1], operands[0]));
477690075Sobrien	          else
477790075Sobrien		   emit_insn (gen_storehi (operands[1], operands[0]));
477890075Sobrien	        }
477990075Sobrien	      DONE;
478090075Sobrien	    }
478190075Sobrien          /* Sign extend a constant, and keep it in an SImode reg.  */
478290075Sobrien          else if (GET_CODE (operands[1]) == CONST_INT)
478390075Sobrien	    {
478490075Sobrien	      rtx reg = gen_reg_rtx (SImode);
478590075Sobrien	      HOST_WIDE_INT val = INTVAL (operands[1]) & 0xffff;
478690075Sobrien
478790075Sobrien	      /* If the constant is already valid, leave it alone.  */
478890075Sobrien	      if (!const_ok_for_arm (val))
478990075Sobrien	        {
479090075Sobrien	          /* If setting all the top bits will make the constant 
479190075Sobrien		     loadable in a single instruction, then set them.  
479290075Sobrien		     Otherwise, sign extend the number.  */
479390075Sobrien
479490075Sobrien	          if (const_ok_for_arm (~(val | ~0xffff)))
479590075Sobrien		    val |= ~0xffff;
479690075Sobrien	          else if (val & 0x8000)
479790075Sobrien		    val |= ~0xffff;
479890075Sobrien	        }
479990075Sobrien
480090075Sobrien	      emit_insn (gen_movsi (reg, GEN_INT (val)));
4801102780Skan	      operands[1] = gen_lowpart (HImode, reg);
480290075Sobrien	    }
4803169689Skan	  else if (arm_arch4 && optimize && !no_new_pseudos
4804117395Skan		   && GET_CODE (operands[1]) == MEM)
4805117395Skan	    {
4806117395Skan	      rtx reg = gen_reg_rtx (SImode);
4807117395Skan
4808117395Skan	      emit_insn (gen_zero_extendhisi2 (reg, operands[1]));
4809117395Skan	      operands[1] = gen_lowpart (HImode, reg);
4810117395Skan	    }
481190075Sobrien          else if (!arm_arch4)
481290075Sobrien	    {
481390075Sobrien	      if (GET_CODE (operands[1]) == MEM)
481490075Sobrien	        {
4815169689Skan		  rtx base;
4816169689Skan		  rtx offset = const0_rtx;
4817169689Skan		  rtx reg = gen_reg_rtx (SImode);
4818169689Skan
4819169689Skan		  if ((GET_CODE (base = XEXP (operands[1], 0)) == REG
4820169689Skan		       || (GET_CODE (base) == PLUS
4821169689Skan			   && (GET_CODE (offset = XEXP (base, 1))
4822169689Skan			       == CONST_INT)
4823169689Skan                           && ((INTVAL(offset) & 1) != 1)
4824169689Skan			   && GET_CODE (base = XEXP (base, 0)) == REG))
4825169689Skan		      && REGNO_POINTER_ALIGN (REGNO (base)) >= 32)
482690075Sobrien		    {
4827169689Skan		      rtx new;
482890075Sobrien
4829169689Skan		      new = widen_memory_access (operands[1], SImode,
4830169689Skan						 ((INTVAL (offset) & ~3)
4831169689Skan						  - INTVAL (offset)));
4832169689Skan		      emit_insn (gen_movsi (reg, new));
4833169689Skan		      if (((INTVAL (offset) & 2) != 0)
4834169689Skan			  ^ (BYTES_BIG_ENDIAN ? 1 : 0))
4835169689Skan			{
4836169689Skan			  rtx reg2 = gen_reg_rtx (SImode);
483790075Sobrien
4838169689Skan			  emit_insn (gen_lshrsi3 (reg2, reg, GEN_INT (16)));
4839169689Skan			  reg = reg2;
4840169689Skan			}
484190075Sobrien		    }
4842169689Skan		  else
4843169689Skan		    emit_insn (gen_movhi_bytes (reg, operands[1]));
484490075Sobrien
4845169689Skan		  operands[1] = gen_lowpart (HImode, reg);
484690075Sobrien	       }
484790075Sobrien	   }
484890075Sobrien        }
4849132718Skan      /* Handle loading a large integer during reload.  */
485090075Sobrien      else if (GET_CODE (operands[1]) == CONST_INT
485190075Sobrien	       && !const_ok_for_arm (INTVAL (operands[1]))
485290075Sobrien	       && !const_ok_for_arm (~INTVAL (operands[1])))
485390075Sobrien        {
485490075Sobrien          /* Writing a constant to memory needs a scratch, which should
485590075Sobrien	     be handled with SECONDARY_RELOADs.  */
4856169689Skan          gcc_assert (GET_CODE (operands[0]) == REG);
485790075Sobrien
485890075Sobrien          operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0);
485990075Sobrien          emit_insn (gen_movsi (operands[0], operands[1]));
486090075Sobrien          DONE;
486190075Sobrien       }
486290075Sobrien    }
486390075Sobrien  else /* TARGET_THUMB */
486490075Sobrien    {
486590075Sobrien      if (!no_new_pseudos)
486690075Sobrien        {
4867169689Skan	  if (GET_CODE (operands[1]) == CONST_INT)
4868169689Skan	    {
4869169689Skan	      rtx reg = gen_reg_rtx (SImode);
487090075Sobrien
4871169689Skan	      emit_insn (gen_movsi (reg, operands[1]));
4872169689Skan	      operands[1] = gen_lowpart (HImode, reg);
4873169689Skan	    }
4874169689Skan
487590075Sobrien          /* ??? We shouldn't really get invalid addresses here, but this can
487690075Sobrien	     happen if we are passed a SP (never OK for HImode/QImode) or 
487790075Sobrien	     virtual register (rejected by GO_IF_LEGITIMATE_ADDRESS for 
487890075Sobrien	     HImode/QImode) relative address.  */
487990075Sobrien          /* ??? This should perhaps be fixed elsewhere, for instance, in
488090075Sobrien	     fixup_stack_1, by checking for other kinds of invalid addresses,
488190075Sobrien	     e.g. a bare reference to a virtual register.  This may confuse the
488290075Sobrien	     alpha though, which must handle this case differently.  */
488390075Sobrien          if (GET_CODE (operands[0]) == MEM
488490075Sobrien	      && !memory_address_p (GET_MODE (operands[0]),
488590075Sobrien				    XEXP (operands[0], 0)))
488690075Sobrien	    operands[0]
488790075Sobrien	      = replace_equiv_address (operands[0],
488890075Sobrien				       copy_to_reg (XEXP (operands[0], 0)));
488990075Sobrien   
489090075Sobrien          if (GET_CODE (operands[1]) == MEM
489190075Sobrien	      && !memory_address_p (GET_MODE (operands[1]),
489290075Sobrien				    XEXP (operands[1], 0)))
489390075Sobrien	    operands[1]
489490075Sobrien	      = replace_equiv_address (operands[1],
489590075Sobrien				       copy_to_reg (XEXP (operands[1], 0)));
4896169689Skan
4897169689Skan	  if (GET_CODE (operands[1]) == MEM && optimize > 0)
4898169689Skan	    {
4899169689Skan	      rtx reg = gen_reg_rtx (SImode);
4900169689Skan
4901169689Skan	      emit_insn (gen_zero_extendhisi2 (reg, operands[1]));
4902169689Skan	      operands[1] = gen_lowpart (HImode, reg);
4903169689Skan	    }
4904169689Skan
4905169689Skan          if (GET_CODE (operands[0]) == MEM)
4906169689Skan	    operands[1] = force_reg (HImode, operands[1]);
490790075Sobrien        }
490890075Sobrien      else if (GET_CODE (operands[1]) == CONST_INT
4909169689Skan	        && !satisfies_constraint_I (operands[1]))
491090075Sobrien        {
4911169689Skan	  /* Handle loading a large integer during reload.  */
4912169689Skan
491390075Sobrien          /* Writing a constant to memory needs a scratch, which should
491490075Sobrien	     be handled with SECONDARY_RELOADs.  */
4915169689Skan          gcc_assert (GET_CODE (operands[0]) == REG);
491690075Sobrien
4917169689Skan          operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0);
491890075Sobrien          emit_insn (gen_movsi (operands[0], operands[1]));
491990075Sobrien          DONE;
492090075Sobrien        }
492190075Sobrien    }
492290075Sobrien  "
492390075Sobrien)
492490075Sobrien
492590075Sobrien(define_insn "*thumb_movhi_insn"
4926132718Skan  [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l")
4927132718Skan	(match_operand:HI 1 "general_operand"       "l,m,l,*h,*r,I"))]
492890075Sobrien  "TARGET_THUMB
492990075Sobrien   && (   register_operand (operands[0], HImode)
493090075Sobrien       || register_operand (operands[1], HImode))"
493190075Sobrien  "*
493290075Sobrien  switch (which_alternative)
493390075Sobrien    {
493490075Sobrien    case 0: return \"add	%0, %1, #0\";
493590075Sobrien    case 2: return \"strh	%1, %0\";
493690075Sobrien    case 3: return \"mov	%0, %1\";
493790075Sobrien    case 4: return \"mov	%0, %1\";
493890075Sobrien    case 5: return \"mov	%0, %1\";
4939169689Skan    default: gcc_unreachable ();
494090075Sobrien    case 1:
494190075Sobrien      /* The stack pointer can end up being taken as an index register.
494290075Sobrien          Catch this case here and deal with it.  */
494390075Sobrien      if (GET_CODE (XEXP (operands[1], 0)) == PLUS
494490075Sobrien	  && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == REG
494590075Sobrien	  && REGNO    (XEXP (XEXP (operands[1], 0), 0)) == SP_REGNUM)
494690075Sobrien        {
494790075Sobrien	  rtx ops[2];
494890075Sobrien          ops[0] = operands[0];
494990075Sobrien          ops[1] = XEXP (XEXP (operands[1], 0), 0);
495090075Sobrien      
495190075Sobrien          output_asm_insn (\"mov	%0, %1\", ops);
495290075Sobrien
495390075Sobrien          XEXP (XEXP (operands[1], 0), 0) = operands[0];
495490075Sobrien    
495590075Sobrien	}
495690075Sobrien      return \"ldrh	%0, %1\";
495790075Sobrien    }"
495890075Sobrien  [(set_attr "length" "2,4,2,2,2,2")
4959169689Skan   (set_attr "type" "*,load1,store1,*,*,*")]
496090075Sobrien)
496190075Sobrien
496290075Sobrien
496390075Sobrien(define_expand "movhi_bytes"
496490075Sobrien  [(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" "")))
496590075Sobrien   (set (match_dup 3)
496690075Sobrien	(zero_extend:SI (match_dup 6)))
496790075Sobrien   (set (match_operand:SI 0 "" "")
496890075Sobrien	 (ior:SI (ashift:SI (match_dup 4) (const_int 8)) (match_dup 5)))]
496990075Sobrien  "TARGET_ARM"
497090075Sobrien  "
497190075Sobrien  {
497290075Sobrien    rtx mem1, mem2;
497390075Sobrien    rtx addr = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
497490075Sobrien
4975169689Skan    mem1 = change_address (operands[1], QImode, addr);
4976169689Skan    mem2 = change_address (operands[1], QImode, plus_constant (addr, 1));
497790075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
497890075Sobrien    operands[1] = mem1;
497990075Sobrien    operands[2] = gen_reg_rtx (SImode);
498090075Sobrien    operands[3] = gen_reg_rtx (SImode);
498190075Sobrien    operands[6] = mem2;
498290075Sobrien
498390075Sobrien    if (BYTES_BIG_ENDIAN)
498490075Sobrien      {
498590075Sobrien	operands[4] = operands[2];
498690075Sobrien	operands[5] = operands[3];
498790075Sobrien      }
498890075Sobrien    else
498990075Sobrien      {
499090075Sobrien	operands[4] = operands[3];
499190075Sobrien	operands[5] = operands[2];
499290075Sobrien      }
499390075Sobrien  }"
499490075Sobrien)
499590075Sobrien
499690075Sobrien(define_expand "movhi_bigend"
499790075Sobrien  [(set (match_dup 2)
499890075Sobrien	(rotate:SI (subreg:SI (match_operand:HI 1 "memory_operand" "") 0)
499990075Sobrien		   (const_int 16)))
500090075Sobrien   (set (match_dup 3)
500190075Sobrien	(ashiftrt:SI (match_dup 2) (const_int 16)))
500290075Sobrien   (set (match_operand:HI 0 "s_register_operand" "")
5003132718Skan	(match_dup 4))]
500490075Sobrien  "TARGET_ARM"
500590075Sobrien  "
500690075Sobrien  operands[2] = gen_reg_rtx (SImode);
500790075Sobrien  operands[3] = gen_reg_rtx (SImode);
5008132718Skan  operands[4] = gen_lowpart (HImode, operands[3]);
500990075Sobrien  "
501090075Sobrien)
501190075Sobrien
5012117395Skan;; Pattern to recognize insn generated default case above
501390075Sobrien(define_insn "*movhi_insn_arch4"
501490075Sobrien  [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,m,r")    
501590075Sobrien	(match_operand:HI 1 "general_operand"      "rI,K,r,m"))]
501690075Sobrien  "TARGET_ARM
501790075Sobrien   && arm_arch4
501890075Sobrien   && (GET_CODE (operands[1]) != CONST_INT
501990075Sobrien       || const_ok_for_arm (INTVAL (operands[1]))
502090075Sobrien       || const_ok_for_arm (~INTVAL (operands[1])))"
502190075Sobrien  "@
502290075Sobrien   mov%?\\t%0, %1\\t%@ movhi
502390075Sobrien   mvn%?\\t%0, #%B1\\t%@ movhi
5024169689Skan   str%?h\\t%1, %0\\t%@ movhi
502590075Sobrien   ldr%?h\\t%0, %1\\t%@ movhi"
5026169689Skan  [(set_attr "type" "*,*,store1,load1")
502790075Sobrien   (set_attr "predicable" "yes")
502890075Sobrien   (set_attr "pool_range" "*,*,*,256")
502990075Sobrien   (set_attr "neg_pool_range" "*,*,*,244")]
503090075Sobrien)
503190075Sobrien
503290075Sobrien(define_insn "*movhi_bytes"
503390075Sobrien  [(set (match_operand:HI 0 "s_register_operand" "=r,r")
503490075Sobrien	(match_operand:HI 1 "arm_rhs_operand"  "rI,K"))]
5035169689Skan  "TARGET_ARM"
503690075Sobrien  "@
503790075Sobrien   mov%?\\t%0, %1\\t%@ movhi
503890075Sobrien   mvn%?\\t%0, #%B1\\t%@ movhi"
503990075Sobrien  [(set_attr "predicable" "yes")]
504090075Sobrien)
504190075Sobrien
5042169689Skan(define_expand "thumb_movhi_clobber"
5043169689Skan  [(set (match_operand:HI     0 "memory_operand"   "")
5044169689Skan	(match_operand:HI     1 "register_operand" ""))
5045169689Skan   (clobber (match_operand:DI 2 "register_operand" ""))]
504690075Sobrien  "TARGET_THUMB"
5047169689Skan  "
5048169689Skan  if (strict_memory_address_p (HImode, XEXP (operands[0], 0))
5049169689Skan      && REGNO (operands[1]) <= LAST_LO_REGNUM)
5050169689Skan    {
5051169689Skan      emit_insn (gen_movhi (operands[0], operands[1]));
5052169689Skan      DONE;
5053169689Skan    }
5054169689Skan  /* XXX Fixme, need to handle other cases here as well.  */
5055169689Skan  gcc_unreachable ();
5056169689Skan  "
505790075Sobrien)
505890075Sobrien	
505990075Sobrien;; We use a DImode scratch because we may occasionally need an additional
506090075Sobrien;; temporary if the address isn't offsettable -- push_reload doesn't seem
506190075Sobrien;; to take any notice of the "o" constraints on reload_memory_operand operand.
506290075Sobrien(define_expand "reload_outhi"
506390075Sobrien  [(parallel [(match_operand:HI 0 "arm_reload_memory_operand" "=o")
506490075Sobrien	      (match_operand:HI 1 "s_register_operand"        "r")
506590075Sobrien	      (match_operand:DI 2 "s_register_operand"        "=&l")])]
506690075Sobrien  "TARGET_EITHER"
506790075Sobrien  "if (TARGET_ARM)
506890075Sobrien     arm_reload_out_hi (operands);
506990075Sobrien   else
507090075Sobrien     thumb_reload_out_hi (operands);
507190075Sobrien  DONE;
507290075Sobrien  "
507390075Sobrien)
507490075Sobrien
507590075Sobrien(define_expand "reload_inhi"
507690075Sobrien  [(parallel [(match_operand:HI 0 "s_register_operand" "=r")
507790075Sobrien	      (match_operand:HI 1 "arm_reload_memory_operand" "o")
507890075Sobrien	      (match_operand:DI 2 "s_register_operand" "=&r")])]
5079169689Skan  "TARGET_EITHER"
508090075Sobrien  "
508190075Sobrien  if (TARGET_ARM)
508290075Sobrien    arm_reload_in_hi (operands);
508390075Sobrien  else
508490075Sobrien    thumb_reload_out_hi (operands);
508590075Sobrien  DONE;
508690075Sobrien")
508790075Sobrien
508890075Sobrien(define_expand "movqi"
508990075Sobrien  [(set (match_operand:QI 0 "general_operand" "")
509090075Sobrien        (match_operand:QI 1 "general_operand" ""))]
509190075Sobrien  "TARGET_EITHER"
509290075Sobrien  "
5093169689Skan  /* Everything except mem = const or mem = mem can be done easily */
5094169689Skan
5095169689Skan  if (!no_new_pseudos)
509690075Sobrien    {
5097169689Skan      if (GET_CODE (operands[1]) == CONST_INT)
5098169689Skan	{
5099169689Skan	  rtx reg = gen_reg_rtx (SImode);
510090075Sobrien
5101169689Skan	  emit_insn (gen_movsi (reg, operands[1]));
5102169689Skan	  operands[1] = gen_lowpart (QImode, reg);
5103169689Skan	}
510490075Sobrien
5105169689Skan      if (TARGET_THUMB)
5106169689Skan	{
510790075Sobrien          /* ??? We shouldn't really get invalid addresses here, but this can
510890075Sobrien	     happen if we are passed a SP (never OK for HImode/QImode) or
510990075Sobrien	     virtual register (rejected by GO_IF_LEGITIMATE_ADDRESS for
511090075Sobrien	     HImode/QImode) relative address.  */
511190075Sobrien          /* ??? This should perhaps be fixed elsewhere, for instance, in
511290075Sobrien	     fixup_stack_1, by checking for other kinds of invalid addresses,
511390075Sobrien	     e.g. a bare reference to a virtual register.  This may confuse the
511490075Sobrien	     alpha though, which must handle this case differently.  */
511590075Sobrien          if (GET_CODE (operands[0]) == MEM
511690075Sobrien	      && !memory_address_p (GET_MODE (operands[0]),
511790075Sobrien		  		     XEXP (operands[0], 0)))
511890075Sobrien	    operands[0]
511990075Sobrien	      = replace_equiv_address (operands[0],
512090075Sobrien				       copy_to_reg (XEXP (operands[0], 0)));
512190075Sobrien          if (GET_CODE (operands[1]) == MEM
512290075Sobrien	      && !memory_address_p (GET_MODE (operands[1]),
512390075Sobrien				    XEXP (operands[1], 0)))
512490075Sobrien	     operands[1]
512590075Sobrien	       = replace_equiv_address (operands[1],
512690075Sobrien					copy_to_reg (XEXP (operands[1], 0)));
5127169689Skan	}
5128169689Skan
5129169689Skan      if (GET_CODE (operands[1]) == MEM && optimize > 0)
5130169689Skan	{
5131169689Skan	  rtx reg = gen_reg_rtx (SImode);
5132169689Skan
5133169689Skan	  emit_insn (gen_zero_extendqisi2 (reg, operands[1]));
5134169689Skan	  operands[1] = gen_lowpart (QImode, reg);
5135169689Skan	}
5136169689Skan
5137169689Skan      if (GET_CODE (operands[0]) == MEM)
5138169689Skan	operands[1] = force_reg (QImode, operands[1]);
5139169689Skan    }
5140169689Skan  else if (TARGET_THUMB
5141169689Skan	   && GET_CODE (operands[1]) == CONST_INT
5142169689Skan	   && !satisfies_constraint_I (operands[1]))
5143169689Skan    {
5144132718Skan      /* Handle loading a large integer during reload.  */
514590075Sobrien
5146169689Skan      /* Writing a constant to memory needs a scratch, which should
5147169689Skan	 be handled with SECONDARY_RELOADs.  */
5148169689Skan      gcc_assert (GET_CODE (operands[0]) == REG);
5149169689Skan
5150169689Skan      operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0);
5151169689Skan      emit_insn (gen_movsi (operands[0], operands[1]));
5152169689Skan      DONE;
515390075Sobrien    }
515490075Sobrien  "
515590075Sobrien)
515690075Sobrien
515790075Sobrien
515890075Sobrien(define_insn "*arm_movqi_insn"
515990075Sobrien  [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r,m")
516090075Sobrien	(match_operand:QI 1 "general_operand" "rI,K,m,r"))]
516190075Sobrien  "TARGET_ARM
516290075Sobrien   && (   register_operand (operands[0], QImode)
516390075Sobrien       || register_operand (operands[1], QImode))"
516490075Sobrien  "@
516590075Sobrien   mov%?\\t%0, %1
516690075Sobrien   mvn%?\\t%0, #%B1
516790075Sobrien   ldr%?b\\t%0, %1
516890075Sobrien   str%?b\\t%1, %0"
5169169689Skan  [(set_attr "type" "*,*,load1,store1")
517090075Sobrien   (set_attr "predicable" "yes")]
517190075Sobrien)
517290075Sobrien
517390075Sobrien(define_insn "*thumb_movqi_insn"
517490075Sobrien  [(set (match_operand:QI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l")
517590075Sobrien	(match_operand:QI 1 "general_operand"      "l, m,l,*h,*r,I"))]
517690075Sobrien  "TARGET_THUMB
517790075Sobrien   && (   register_operand (operands[0], QImode)
517890075Sobrien       || register_operand (operands[1], QImode))"
517990075Sobrien  "@
518090075Sobrien   add\\t%0, %1, #0
518190075Sobrien   ldrb\\t%0, %1
518290075Sobrien   strb\\t%1, %0
518390075Sobrien   mov\\t%0, %1
518490075Sobrien   mov\\t%0, %1
518590075Sobrien   mov\\t%0, %1"
518690075Sobrien  [(set_attr "length" "2")
5187169689Skan   (set_attr "type" "*,load1,store1,*,*,*")
518890075Sobrien   (set_attr "pool_range" "*,32,*,*,*,*")]
518990075Sobrien)
519090075Sobrien
519190075Sobrien(define_expand "movsf"
519290075Sobrien  [(set (match_operand:SF 0 "general_operand" "")
519390075Sobrien	(match_operand:SF 1 "general_operand" ""))]
519490075Sobrien  "TARGET_EITHER"
519590075Sobrien  "
519690075Sobrien  if (TARGET_ARM)
519790075Sobrien    {
519890075Sobrien      if (GET_CODE (operands[0]) == MEM)
519990075Sobrien        operands[1] = force_reg (SFmode, operands[1]);
520090075Sobrien    }
520190075Sobrien  else /* TARGET_THUMB */
520290075Sobrien    {
520390075Sobrien      if (!no_new_pseudos)
520490075Sobrien        {
520590075Sobrien           if (GET_CODE (operands[0]) != REG)
520690075Sobrien	     operands[1] = force_reg (SFmode, operands[1]);
520790075Sobrien        }
520890075Sobrien    }
520990075Sobrien  "
521090075Sobrien)
521190075Sobrien
5212169689Skan;; Transform a floating-point move of a constant into a core register into
5213169689Skan;; an SImode operation.
521490075Sobrien(define_split
5215169689Skan  [(set (match_operand:SF 0 "arm_general_register_operand" "")
521690075Sobrien	(match_operand:SF 1 "immediate_operand" ""))]
521790075Sobrien  "TARGET_ARM
521890075Sobrien   && reload_completed
521990075Sobrien   && GET_CODE (operands[1]) == CONST_DOUBLE"
522090075Sobrien  [(set (match_dup 2) (match_dup 3))]
522190075Sobrien  "
522290075Sobrien  operands[2] = gen_lowpart (SImode, operands[0]);
522390075Sobrien  operands[3] = gen_lowpart (SImode, operands[1]);
522490075Sobrien  if (operands[2] == 0 || operands[3] == 0)
522590075Sobrien    FAIL;
522690075Sobrien  "
522790075Sobrien)
522890075Sobrien
522990075Sobrien(define_insn "*arm_movsf_soft_insn"
523090075Sobrien  [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m")
523190075Sobrien	(match_operand:SF 1 "general_operand"  "r,mE,r"))]
523290075Sobrien  "TARGET_ARM
523390075Sobrien   && TARGET_SOFT_FLOAT
523490075Sobrien   && (GET_CODE (operands[0]) != MEM
523590075Sobrien       || register_operand (operands[1], SFmode))"
523690075Sobrien  "@
523790075Sobrien   mov%?\\t%0, %1
523890075Sobrien   ldr%?\\t%0, %1\\t%@ float
523990075Sobrien   str%?\\t%1, %0\\t%@ float"
524090075Sobrien  [(set_attr "length" "4,4,4")
524190075Sobrien   (set_attr "predicable" "yes")
5242169689Skan   (set_attr "type" "*,load1,store1")
524390075Sobrien   (set_attr "pool_range" "*,4096,*")
524490075Sobrien   (set_attr "neg_pool_range" "*,4084,*")]
524590075Sobrien)
524690075Sobrien
524790075Sobrien;;; ??? This should have alternatives for constants.
524890075Sobrien(define_insn "*thumb_movsf_insn"
524990075Sobrien  [(set (match_operand:SF     0 "nonimmediate_operand" "=l,l,>,l, m,*r,*h")
525090075Sobrien	(match_operand:SF     1 "general_operand"      "l, >,l,mF,l,*h,*r"))]
525190075Sobrien  "TARGET_THUMB
525290075Sobrien   && (   register_operand (operands[0], SFmode) 
525390075Sobrien       || register_operand (operands[1], SFmode))"
525490075Sobrien  "@
525590075Sobrien   add\\t%0, %1, #0
525690075Sobrien   ldmia\\t%1, {%0}
525790075Sobrien   stmia\\t%0, {%1}
525890075Sobrien   ldr\\t%0, %1
525990075Sobrien   str\\t%1, %0
526090075Sobrien   mov\\t%0, %1
526190075Sobrien   mov\\t%0, %1"
526290075Sobrien  [(set_attr "length" "2")
5263169689Skan   (set_attr "type" "*,load1,store1,load1,store1,*,*")
526490075Sobrien   (set_attr "pool_range" "*,*,*,1020,*,*,*")]
526590075Sobrien)
526690075Sobrien
526790075Sobrien(define_expand "movdf"
526890075Sobrien  [(set (match_operand:DF 0 "general_operand" "")
526990075Sobrien	(match_operand:DF 1 "general_operand" ""))]
527090075Sobrien  "TARGET_EITHER"
527190075Sobrien  "
527290075Sobrien  if (TARGET_ARM)
527390075Sobrien    {
527490075Sobrien      if (GET_CODE (operands[0]) == MEM)
527590075Sobrien        operands[1] = force_reg (DFmode, operands[1]);
527690075Sobrien    }
527790075Sobrien  else /* TARGET_THUMB */
527890075Sobrien    {
527990075Sobrien      if (!no_new_pseudos)
528090075Sobrien        {
528190075Sobrien          if (GET_CODE (operands[0]) != REG)
528290075Sobrien	    operands[1] = force_reg (DFmode, operands[1]);
528390075Sobrien        }
528490075Sobrien    }
528590075Sobrien  "
528690075Sobrien)
528790075Sobrien
528890075Sobrien;; Reloading a df mode value stored in integer regs to memory can require a
528990075Sobrien;; scratch reg.
529090075Sobrien(define_expand "reload_outdf"
529190075Sobrien  [(match_operand:DF 0 "arm_reload_memory_operand" "=o")
529290075Sobrien   (match_operand:DF 1 "s_register_operand" "r")
529390075Sobrien   (match_operand:SI 2 "s_register_operand" "=&r")]
529490075Sobrien  "TARGET_ARM"
529590075Sobrien  "
529690075Sobrien  {
529790075Sobrien    enum rtx_code code = GET_CODE (XEXP (operands[0], 0));
529890075Sobrien
529990075Sobrien    if (code == REG)
530090075Sobrien      operands[2] = XEXP (operands[0], 0);
530190075Sobrien    else if (code == POST_INC || code == PRE_DEC)
530290075Sobrien      {
530390075Sobrien	operands[0] = gen_rtx_SUBREG (DImode, operands[0], 0);
530490075Sobrien	operands[1] = gen_rtx_SUBREG (DImode, operands[1], 0);
530590075Sobrien	emit_insn (gen_movdi (operands[0], operands[1]));
530690075Sobrien	DONE;
530790075Sobrien      }
530890075Sobrien    else if (code == PRE_INC)
530990075Sobrien      {
531090075Sobrien	rtx reg = XEXP (XEXP (operands[0], 0), 0);
531190075Sobrien
531290075Sobrien	emit_insn (gen_addsi3 (reg, reg, GEN_INT (8)));
531390075Sobrien	operands[2] = reg;
531490075Sobrien      }
531590075Sobrien    else if (code == POST_DEC)
531690075Sobrien      operands[2] = XEXP (XEXP (operands[0], 0), 0);
531790075Sobrien    else
531890075Sobrien      emit_insn (gen_addsi3 (operands[2], XEXP (XEXP (operands[0], 0), 0),
531990075Sobrien			     XEXP (XEXP (operands[0], 0), 1)));
532090075Sobrien
5321169689Skan    emit_insn (gen_rtx_SET (VOIDmode,
5322169689Skan			    replace_equiv_address (operands[0], operands[2]),
532390075Sobrien			    operands[1]));
532490075Sobrien
532590075Sobrien    if (code == POST_DEC)
532690075Sobrien      emit_insn (gen_addsi3 (operands[2], operands[2], GEN_INT (-8)));
532790075Sobrien
532890075Sobrien    DONE;
532990075Sobrien  }"
533090075Sobrien)
533190075Sobrien
533290075Sobrien(define_insn "*movdf_soft_insn"
5333169689Skan  [(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=r,r,r,r,m")
5334169689Skan	(match_operand:DF 1 "soft_df_operand" "rDa,Db,Dc,mF,r"))]
533590075Sobrien  "TARGET_ARM && TARGET_SOFT_FLOAT
5336169689Skan   && (   register_operand (operands[0], DFmode)
5337169689Skan       || register_operand (operands[1], DFmode))"
5338169689Skan  "*
5339169689Skan  switch (which_alternative)
5340169689Skan    {
5341169689Skan    case 0:
5342169689Skan    case 1:
5343169689Skan    case 2:
5344169689Skan      return \"#\";
5345169689Skan    default:
5346169689Skan      return output_move_double (operands);
5347169689Skan    }
534890075Sobrien  "
5349169689Skan  [(set_attr "length" "8,12,16,8,8")
5350169689Skan   (set_attr "type" "*,*,*,load2,store2")
535196263Sobrien   (set_attr "pool_range" "1020")
535296263Sobrien   (set_attr "neg_pool_range" "1008")]
535390075Sobrien)
535490075Sobrien
535590075Sobrien;;; ??? This should have alternatives for constants.
535690075Sobrien;;; ??? This was originally identical to the movdi_insn pattern.
535790075Sobrien;;; ??? The 'F' constraint looks funny, but it should always be replaced by
535890075Sobrien;;; thumb_reorg with a memory reference.
535990075Sobrien(define_insn "*thumb_movdf_insn"
536090075Sobrien  [(set (match_operand:DF 0 "nonimmediate_operand" "=l,l,>,l, m,*r")
536190075Sobrien	(match_operand:DF 1 "general_operand"      "l, >,l,mF,l,*r"))]
536290075Sobrien  "TARGET_THUMB
536390075Sobrien   && (   register_operand (operands[0], DFmode)
536490075Sobrien       || register_operand (operands[1], DFmode))"
536590075Sobrien  "*
536690075Sobrien  switch (which_alternative)
536790075Sobrien    {
536890075Sobrien    default:
536990075Sobrien    case 0:
537090075Sobrien      if (REGNO (operands[1]) == REGNO (operands[0]) + 1)
537190075Sobrien	return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\";
537290075Sobrien      return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\";
537390075Sobrien    case 1:
537490075Sobrien      return \"ldmia\\t%1, {%0, %H0}\";
537590075Sobrien    case 2:
537690075Sobrien      return \"stmia\\t%0, {%1, %H1}\";
537790075Sobrien    case 3:
537890075Sobrien      return thumb_load_double_from_address (operands);
537990075Sobrien    case 4:
5380169689Skan      operands[2] = gen_rtx_MEM (SImode,
5381169689Skan				 plus_constant (XEXP (operands[0], 0), 4));
538290075Sobrien      output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands);
538390075Sobrien      return \"\";
538490075Sobrien    case 5:
538590075Sobrien      if (REGNO (operands[1]) == REGNO (operands[0]) + 1)
538690075Sobrien	return \"mov\\t%0, %1\;mov\\t%H0, %H1\";
538790075Sobrien      return \"mov\\t%H0, %H1\;mov\\t%0, %1\";
538890075Sobrien    }
538990075Sobrien  "
539090075Sobrien  [(set_attr "length" "4,2,2,6,4,4")
5391169689Skan   (set_attr "type" "*,load2,store2,load2,store2,*")
539290075Sobrien   (set_attr "pool_range" "*,*,*,1020,*,*")]
539390075Sobrien)
539490075Sobrien
5395169689Skan(define_expand "movxf"
5396169689Skan  [(set (match_operand:XF 0 "general_operand" "")
5397169689Skan	(match_operand:XF 1 "general_operand" ""))]
5398169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
5399169689Skan  "
5400169689Skan  if (GET_CODE (operands[0]) == MEM)
5401169689Skan    operands[1] = force_reg (XFmode, operands[1]);
5402169689Skan  "
5403169689Skan)
5404169689Skan
5405132718Skan;; Vector Moves
5406132718Skan(define_expand "movv2si"
5407132718Skan  [(set (match_operand:V2SI 0 "nonimmediate_operand" "")
5408132718Skan	(match_operand:V2SI 1 "general_operand" ""))]
5409132718Skan  "TARGET_REALLY_IWMMXT"
5410132718Skan{
5411132718Skan})
541290075Sobrien
5413132718Skan(define_expand "movv4hi"
5414132718Skan  [(set (match_operand:V4HI 0 "nonimmediate_operand" "")
5415132718Skan	(match_operand:V4HI 1 "general_operand" ""))]
5416132718Skan  "TARGET_REALLY_IWMMXT"
5417132718Skan{
5418132718Skan})
541990075Sobrien
5420132718Skan(define_expand "movv8qi"
5421132718Skan  [(set (match_operand:V8QI 0 "nonimmediate_operand" "")
5422132718Skan	(match_operand:V8QI 1 "general_operand" ""))]
5423132718Skan  "TARGET_REALLY_IWMMXT"
5424132718Skan{
5425132718Skan})
542690075Sobrien
542790075Sobrien
542890075Sobrien;; load- and store-multiple insns
542990075Sobrien;; The arm can load/store any set of registers, provided that they are in
543090075Sobrien;; ascending order; but that is beyond GCC so stick with what it knows.
543190075Sobrien
543290075Sobrien(define_expand "load_multiple"
543390075Sobrien  [(match_par_dup 3 [(set (match_operand:SI 0 "" "")
543490075Sobrien                          (match_operand:SI 1 "" ""))
543590075Sobrien                     (use (match_operand:SI 2 "" ""))])]
543690075Sobrien  "TARGET_ARM"
5437161651Skan{
5438161651Skan  HOST_WIDE_INT offset = 0;
5439169689Skan
544090075Sobrien  /* Support only fixed point registers.  */
544190075Sobrien  if (GET_CODE (operands[2]) != CONST_INT
544290075Sobrien      || INTVAL (operands[2]) > 14
544390075Sobrien      || INTVAL (operands[2]) < 2
544490075Sobrien      || GET_CODE (operands[1]) != MEM
544590075Sobrien      || GET_CODE (operands[0]) != REG
544690075Sobrien      || REGNO (operands[0]) > (LAST_ARM_REGNUM - 1)
544790075Sobrien      || REGNO (operands[0]) + INTVAL (operands[2]) > LAST_ARM_REGNUM)
544890075Sobrien    FAIL;
544990075Sobrien
545090075Sobrien  operands[3]
545190075Sobrien    = arm_gen_load_multiple (REGNO (operands[0]), INTVAL (operands[2]),
545290075Sobrien			     force_reg (SImode, XEXP (operands[1], 0)),
5453161651Skan			     TRUE, FALSE, operands[1], &offset);
5454161651Skan})
5455161651Skan
545690075Sobrien;; Load multiple with write-back
545790075Sobrien
545890075Sobrien(define_insn "*ldmsi_postinc4"
545990075Sobrien  [(match_parallel 0 "load_multiple_operation"
546090075Sobrien    [(set (match_operand:SI 1 "s_register_operand" "=r")
546190075Sobrien	  (plus:SI (match_operand:SI 2 "s_register_operand" "1")
546290075Sobrien		   (const_int 16)))
546390075Sobrien     (set (match_operand:SI 3 "arm_hard_register_operand" "")
546490075Sobrien	  (mem:SI (match_dup 2)))
546590075Sobrien     (set (match_operand:SI 4 "arm_hard_register_operand" "")
546690075Sobrien	  (mem:SI (plus:SI (match_dup 2) (const_int 4))))
546790075Sobrien     (set (match_operand:SI 5 "arm_hard_register_operand" "")
546890075Sobrien	  (mem:SI (plus:SI (match_dup 2) (const_int 8))))
546990075Sobrien     (set (match_operand:SI 6 "arm_hard_register_operand" "")
547090075Sobrien	  (mem:SI (plus:SI (match_dup 2) (const_int 12))))])]
547190075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 5"
547290075Sobrien  "ldm%?ia\\t%1!, {%3, %4, %5, %6}"
5473169689Skan  [(set_attr "type" "load4")
547490075Sobrien   (set_attr "predicable" "yes")]
547590075Sobrien)
547690075Sobrien
5477169689Skan(define_insn "*ldmsi_postinc4_thumb"
5478169689Skan  [(match_parallel 0 "load_multiple_operation"
5479169689Skan    [(set (match_operand:SI 1 "s_register_operand" "=l")
5480169689Skan	  (plus:SI (match_operand:SI 2 "s_register_operand" "1")
5481169689Skan		   (const_int 16)))
5482169689Skan     (set (match_operand:SI 3 "arm_hard_register_operand" "")
5483169689Skan	  (mem:SI (match_dup 2)))
5484169689Skan     (set (match_operand:SI 4 "arm_hard_register_operand" "")
5485169689Skan	  (mem:SI (plus:SI (match_dup 2) (const_int 4))))
5486169689Skan     (set (match_operand:SI 5 "arm_hard_register_operand" "")
5487169689Skan	  (mem:SI (plus:SI (match_dup 2) (const_int 8))))
5488169689Skan     (set (match_operand:SI 6 "arm_hard_register_operand" "")
5489169689Skan	  (mem:SI (plus:SI (match_dup 2) (const_int 12))))])]
5490169689Skan  "TARGET_THUMB && XVECLEN (operands[0], 0) == 5"
5491169689Skan  "ldmia\\t%1!, {%3, %4, %5, %6}"
5492169689Skan  [(set_attr "type" "load4")]
5493169689Skan)
5494169689Skan
549590075Sobrien(define_insn "*ldmsi_postinc3"
549690075Sobrien  [(match_parallel 0 "load_multiple_operation"
549790075Sobrien    [(set (match_operand:SI 1 "s_register_operand" "=r")
549890075Sobrien	  (plus:SI (match_operand:SI 2 "s_register_operand" "1")
549990075Sobrien		   (const_int 12)))
550090075Sobrien     (set (match_operand:SI 3 "arm_hard_register_operand" "")
550190075Sobrien	  (mem:SI (match_dup 2)))
550290075Sobrien     (set (match_operand:SI 4 "arm_hard_register_operand" "")
550390075Sobrien	  (mem:SI (plus:SI (match_dup 2) (const_int 4))))
550490075Sobrien     (set (match_operand:SI 5 "arm_hard_register_operand" "")
550590075Sobrien	  (mem:SI (plus:SI (match_dup 2) (const_int 8))))])]
550690075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 4"
550790075Sobrien  "ldm%?ia\\t%1!, {%3, %4, %5}"
5508169689Skan  [(set_attr "type" "load3")
550990075Sobrien   (set_attr "predicable" "yes")]
551090075Sobrien)
551190075Sobrien
551290075Sobrien(define_insn "*ldmsi_postinc2"
551390075Sobrien  [(match_parallel 0 "load_multiple_operation"
551490075Sobrien    [(set (match_operand:SI 1 "s_register_operand" "=r")
551590075Sobrien	  (plus:SI (match_operand:SI 2 "s_register_operand" "1")
551690075Sobrien		   (const_int 8)))
551790075Sobrien     (set (match_operand:SI 3 "arm_hard_register_operand" "")
551890075Sobrien	  (mem:SI (match_dup 2)))
551990075Sobrien     (set (match_operand:SI 4 "arm_hard_register_operand" "")
552090075Sobrien	  (mem:SI (plus:SI (match_dup 2) (const_int 4))))])]
552190075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 3"
552290075Sobrien  "ldm%?ia\\t%1!, {%3, %4}"
5523169689Skan  [(set_attr "type" "load2")
552490075Sobrien   (set_attr "predicable" "yes")]
552590075Sobrien)
552690075Sobrien
552790075Sobrien;; Ordinary load multiple
552890075Sobrien
552990075Sobrien(define_insn "*ldmsi4"
553090075Sobrien  [(match_parallel 0 "load_multiple_operation"
553190075Sobrien    [(set (match_operand:SI 2 "arm_hard_register_operand" "")
553290075Sobrien	  (mem:SI (match_operand:SI 1 "s_register_operand" "r")))
553390075Sobrien     (set (match_operand:SI 3 "arm_hard_register_operand" "")
553490075Sobrien	  (mem:SI (plus:SI (match_dup 1) (const_int 4))))
553590075Sobrien     (set (match_operand:SI 4 "arm_hard_register_operand" "")
553690075Sobrien	  (mem:SI (plus:SI (match_dup 1) (const_int 8))))
553790075Sobrien     (set (match_operand:SI 5 "arm_hard_register_operand" "")
553890075Sobrien	  (mem:SI (plus:SI (match_dup 1) (const_int 12))))])]
553990075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 4"
554090075Sobrien  "ldm%?ia\\t%1, {%2, %3, %4, %5}"
5541169689Skan  [(set_attr "type" "load4")
554290075Sobrien   (set_attr "predicable" "yes")]
554390075Sobrien)
554490075Sobrien
554590075Sobrien(define_insn "*ldmsi3"
554690075Sobrien  [(match_parallel 0 "load_multiple_operation"
554790075Sobrien    [(set (match_operand:SI 2 "arm_hard_register_operand" "")
554890075Sobrien	  (mem:SI (match_operand:SI 1 "s_register_operand" "r")))
554990075Sobrien     (set (match_operand:SI 3 "arm_hard_register_operand" "")
555090075Sobrien	  (mem:SI (plus:SI (match_dup 1) (const_int 4))))
555190075Sobrien     (set (match_operand:SI 4 "arm_hard_register_operand" "")
555290075Sobrien	  (mem:SI (plus:SI (match_dup 1) (const_int 8))))])]
555390075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 3"
555490075Sobrien  "ldm%?ia\\t%1, {%2, %3, %4}"
5555169689Skan  [(set_attr "type" "load3")
555690075Sobrien   (set_attr "predicable" "yes")]
555790075Sobrien)
555890075Sobrien
555990075Sobrien(define_insn "*ldmsi2"
556090075Sobrien  [(match_parallel 0 "load_multiple_operation"
556190075Sobrien    [(set (match_operand:SI 2 "arm_hard_register_operand" "")
556290075Sobrien	  (mem:SI (match_operand:SI 1 "s_register_operand" "r")))
556390075Sobrien     (set (match_operand:SI 3 "arm_hard_register_operand" "")
556490075Sobrien	  (mem:SI (plus:SI (match_dup 1) (const_int 4))))])]
556590075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 2"
556690075Sobrien  "ldm%?ia\\t%1, {%2, %3}"
5567169689Skan  [(set_attr "type" "load2")
556890075Sobrien   (set_attr "predicable" "yes")]
556990075Sobrien)
557090075Sobrien
557190075Sobrien(define_expand "store_multiple"
557290075Sobrien  [(match_par_dup 3 [(set (match_operand:SI 0 "" "")
557390075Sobrien                          (match_operand:SI 1 "" ""))
557490075Sobrien                     (use (match_operand:SI 2 "" ""))])]
557590075Sobrien  "TARGET_ARM"
5576161651Skan{
5577161651Skan  HOST_WIDE_INT offset = 0;
5578161651Skan
5579132718Skan  /* Support only fixed point registers.  */
558090075Sobrien  if (GET_CODE (operands[2]) != CONST_INT
558190075Sobrien      || INTVAL (operands[2]) > 14
558290075Sobrien      || INTVAL (operands[2]) < 2
558390075Sobrien      || GET_CODE (operands[1]) != REG
558490075Sobrien      || GET_CODE (operands[0]) != MEM
558590075Sobrien      || REGNO (operands[1]) > (LAST_ARM_REGNUM - 1)
558690075Sobrien      || REGNO (operands[1]) + INTVAL (operands[2]) > LAST_ARM_REGNUM)
558790075Sobrien    FAIL;
558890075Sobrien
558990075Sobrien  operands[3]
559090075Sobrien    = arm_gen_store_multiple (REGNO (operands[1]), INTVAL (operands[2]),
559190075Sobrien			      force_reg (SImode, XEXP (operands[0], 0)),
5592161651Skan			      TRUE, FALSE, operands[0], &offset);
5593161651Skan})
559490075Sobrien
559590075Sobrien;; Store multiple with write-back
559690075Sobrien
559790075Sobrien(define_insn "*stmsi_postinc4"
559890075Sobrien  [(match_parallel 0 "store_multiple_operation"
559990075Sobrien    [(set (match_operand:SI 1 "s_register_operand" "=r")
560090075Sobrien	  (plus:SI (match_operand:SI 2 "s_register_operand" "1")
560190075Sobrien		   (const_int 16)))
560290075Sobrien     (set (mem:SI (match_dup 2))
560390075Sobrien	  (match_operand:SI 3 "arm_hard_register_operand" ""))
560490075Sobrien     (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
560590075Sobrien	  (match_operand:SI 4 "arm_hard_register_operand" ""))
560690075Sobrien     (set (mem:SI (plus:SI (match_dup 2) (const_int 8)))
560790075Sobrien	  (match_operand:SI 5 "arm_hard_register_operand" ""))
560890075Sobrien     (set (mem:SI (plus:SI (match_dup 2) (const_int 12)))
560990075Sobrien	  (match_operand:SI 6 "arm_hard_register_operand" ""))])]
561090075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 5"
561190075Sobrien  "stm%?ia\\t%1!, {%3, %4, %5, %6}"
561290075Sobrien  [(set_attr "predicable" "yes")
561390075Sobrien   (set_attr "type" "store4")]
561490075Sobrien)
561590075Sobrien
5616169689Skan(define_insn "*stmsi_postinc4_thumb"
5617169689Skan  [(match_parallel 0 "store_multiple_operation"
5618169689Skan    [(set (match_operand:SI 1 "s_register_operand" "=l")
5619169689Skan	  (plus:SI (match_operand:SI 2 "s_register_operand" "1")
5620169689Skan		   (const_int 16)))
5621169689Skan     (set (mem:SI (match_dup 2))
5622169689Skan	  (match_operand:SI 3 "arm_hard_register_operand" ""))
5623169689Skan     (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
5624169689Skan	  (match_operand:SI 4 "arm_hard_register_operand" ""))
5625169689Skan     (set (mem:SI (plus:SI (match_dup 2) (const_int 8)))
5626169689Skan	  (match_operand:SI 5 "arm_hard_register_operand" ""))
5627169689Skan     (set (mem:SI (plus:SI (match_dup 2) (const_int 12)))
5628169689Skan	  (match_operand:SI 6 "arm_hard_register_operand" ""))])]
5629169689Skan  "TARGET_THUMB && XVECLEN (operands[0], 0) == 5"
5630169689Skan  "stmia\\t%1!, {%3, %4, %5, %6}"
5631169689Skan  [(set_attr "type" "store4")]
5632169689Skan)
5633169689Skan
563490075Sobrien(define_insn "*stmsi_postinc3"
563590075Sobrien  [(match_parallel 0 "store_multiple_operation"
563690075Sobrien    [(set (match_operand:SI 1 "s_register_operand" "=r")
563790075Sobrien	  (plus:SI (match_operand:SI 2 "s_register_operand" "1")
563890075Sobrien		   (const_int 12)))
563990075Sobrien     (set (mem:SI (match_dup 2))
564090075Sobrien	  (match_operand:SI 3 "arm_hard_register_operand" ""))
564190075Sobrien     (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
564290075Sobrien	  (match_operand:SI 4 "arm_hard_register_operand" ""))
564390075Sobrien     (set (mem:SI (plus:SI (match_dup 2) (const_int 8)))
564490075Sobrien	  (match_operand:SI 5 "arm_hard_register_operand" ""))])]
564590075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 4"
564690075Sobrien  "stm%?ia\\t%1!, {%3, %4, %5}"
564790075Sobrien  [(set_attr "predicable" "yes")
564890075Sobrien   (set_attr "type" "store3")]
564990075Sobrien)
565090075Sobrien
565190075Sobrien(define_insn "*stmsi_postinc2"
565290075Sobrien  [(match_parallel 0 "store_multiple_operation"
565390075Sobrien    [(set (match_operand:SI 1 "s_register_operand" "=r")
565490075Sobrien	  (plus:SI (match_operand:SI 2 "s_register_operand" "1")
565590075Sobrien		   (const_int 8)))
565690075Sobrien     (set (mem:SI (match_dup 2))
565790075Sobrien	  (match_operand:SI 3 "arm_hard_register_operand" ""))
565890075Sobrien     (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
565990075Sobrien	  (match_operand:SI 4 "arm_hard_register_operand" ""))])]
566090075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 3"
566190075Sobrien  "stm%?ia\\t%1!, {%3, %4}"
566290075Sobrien  [(set_attr "predicable" "yes")
566390075Sobrien   (set_attr "type" "store2")]
566490075Sobrien)
566590075Sobrien
566690075Sobrien;; Ordinary store multiple
566790075Sobrien
566890075Sobrien(define_insn "*stmsi4"
566990075Sobrien  [(match_parallel 0 "store_multiple_operation"
567090075Sobrien    [(set (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
567190075Sobrien	  (match_operand:SI 2 "arm_hard_register_operand" ""))
567290075Sobrien     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
567390075Sobrien	  (match_operand:SI 3 "arm_hard_register_operand" ""))
567490075Sobrien     (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
567590075Sobrien	  (match_operand:SI 4 "arm_hard_register_operand" ""))
567690075Sobrien     (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
567790075Sobrien	  (match_operand:SI 5 "arm_hard_register_operand" ""))])]
567890075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 4"
567990075Sobrien  "stm%?ia\\t%1, {%2, %3, %4, %5}"
568090075Sobrien  [(set_attr "predicable" "yes")
568190075Sobrien   (set_attr "type" "store4")]
568290075Sobrien)
568390075Sobrien
568490075Sobrien(define_insn "*stmsi3"
568590075Sobrien  [(match_parallel 0 "store_multiple_operation"
568690075Sobrien    [(set (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
568790075Sobrien	  (match_operand:SI 2 "arm_hard_register_operand" ""))
568890075Sobrien     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
568990075Sobrien	  (match_operand:SI 3 "arm_hard_register_operand" ""))
569090075Sobrien     (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
569190075Sobrien	  (match_operand:SI 4 "arm_hard_register_operand" ""))])]
569290075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 3"
569390075Sobrien  "stm%?ia\\t%1, {%2, %3, %4}"
569490075Sobrien  [(set_attr "predicable" "yes")
569590075Sobrien   (set_attr "type" "store3")]
569690075Sobrien)
569790075Sobrien
569890075Sobrien(define_insn "*stmsi2"
569990075Sobrien  [(match_parallel 0 "store_multiple_operation"
570090075Sobrien    [(set (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
570190075Sobrien	  (match_operand:SI 2 "arm_hard_register_operand" ""))
570290075Sobrien     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
570390075Sobrien	  (match_operand:SI 3 "arm_hard_register_operand" ""))])]
570490075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 2"
570590075Sobrien  "stm%?ia\\t%1, {%2, %3}"
570690075Sobrien  [(set_attr "predicable" "yes")
570790075Sobrien   (set_attr "type" "store2")]
570890075Sobrien)
570990075Sobrien
571090075Sobrien;; Move a block of memory if it is word aligned and MORE than 2 words long.
571190075Sobrien;; We could let this apply for blocks of less than this, but it clobbers so
571290075Sobrien;; many registers that there is then probably a better way.
571390075Sobrien
5714169689Skan(define_expand "movmemqi"
571590075Sobrien  [(match_operand:BLK 0 "general_operand" "")
571690075Sobrien   (match_operand:BLK 1 "general_operand" "")
571790075Sobrien   (match_operand:SI 2 "const_int_operand" "")
571890075Sobrien   (match_operand:SI 3 "const_int_operand" "")]
571990075Sobrien  "TARGET_EITHER"
572090075Sobrien  "
572190075Sobrien  if (TARGET_ARM)
572290075Sobrien    {
5723169689Skan      if (arm_gen_movmemqi (operands))
572490075Sobrien        DONE;
572590075Sobrien      FAIL;
572690075Sobrien    }
572790075Sobrien  else /* TARGET_THUMB */
572890075Sobrien    {
572990075Sobrien      if (   INTVAL (operands[3]) != 4
573090075Sobrien          || INTVAL (operands[2]) > 48)
573190075Sobrien        FAIL;
573290075Sobrien
5733169689Skan      thumb_expand_movmemqi (operands);
573490075Sobrien      DONE;
573590075Sobrien    }
573690075Sobrien  "
573790075Sobrien)
573890075Sobrien
573990075Sobrien;; Thumb block-move insns
574090075Sobrien
574190075Sobrien(define_insn "movmem12b"
574290075Sobrien  [(set (mem:SI (match_operand:SI 2 "register_operand" "0"))
574390075Sobrien	(mem:SI (match_operand:SI 3 "register_operand" "1")))
574490075Sobrien   (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
574590075Sobrien	(mem:SI (plus:SI (match_dup 3) (const_int 4))))
574690075Sobrien   (set (mem:SI (plus:SI (match_dup 2) (const_int 8)))
574790075Sobrien	(mem:SI (plus:SI (match_dup 3) (const_int 8))))
574890075Sobrien   (set (match_operand:SI 0 "register_operand" "=l")
574990075Sobrien	(plus:SI (match_dup 2) (const_int 12)))
575090075Sobrien   (set (match_operand:SI 1 "register_operand" "=l")
575190075Sobrien	(plus:SI (match_dup 3) (const_int 12)))
575290075Sobrien   (clobber (match_scratch:SI 4 "=&l"))
575390075Sobrien   (clobber (match_scratch:SI 5 "=&l"))
575490075Sobrien   (clobber (match_scratch:SI 6 "=&l"))]
575590075Sobrien  "TARGET_THUMB"
575690075Sobrien  "* return thumb_output_move_mem_multiple (3, operands);"
575790075Sobrien  [(set_attr "length" "4")
575890075Sobrien   ; This isn't entirely accurate...  It loads as well, but in terms of
575990075Sobrien   ; scheduling the following insn it is better to consider it as a store
576090075Sobrien   (set_attr "type" "store3")]
576190075Sobrien)
576290075Sobrien
576390075Sobrien(define_insn "movmem8b"
576490075Sobrien  [(set (mem:SI (match_operand:SI 2 "register_operand" "0"))
576590075Sobrien	(mem:SI (match_operand:SI 3 "register_operand" "1")))
576690075Sobrien   (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
576790075Sobrien	(mem:SI (plus:SI (match_dup 3) (const_int 4))))
576890075Sobrien   (set (match_operand:SI 0 "register_operand" "=l")
576990075Sobrien	(plus:SI (match_dup 2) (const_int 8)))
577090075Sobrien   (set (match_operand:SI 1 "register_operand" "=l")
577190075Sobrien	(plus:SI (match_dup 3) (const_int 8)))
577290075Sobrien   (clobber (match_scratch:SI 4 "=&l"))
577390075Sobrien   (clobber (match_scratch:SI 5 "=&l"))]
577490075Sobrien  "TARGET_THUMB"
577590075Sobrien  "* return thumb_output_move_mem_multiple (2, operands);"
577690075Sobrien  [(set_attr "length" "4")
577790075Sobrien   ; This isn't entirely accurate...  It loads as well, but in terms of
577890075Sobrien   ; scheduling the following insn it is better to consider it as a store
577990075Sobrien   (set_attr "type" "store2")]
578090075Sobrien)
578190075Sobrien
578290075Sobrien
578390075Sobrien
578490075Sobrien;; Compare & branch insns
5785132718Skan;; The range calculations are based as follows:
578690075Sobrien;; For forward branches, the address calculation returns the address of
578790075Sobrien;; the next instruction.  This is 2 beyond the branch instruction.
578890075Sobrien;; For backward branches, the address calculation returns the address of
578990075Sobrien;; the first instruction in this pattern (cmp).  This is 2 before the branch
579090075Sobrien;; instruction for the shortest sequence, and 4 before the branch instruction
579190075Sobrien;; if we have to jump around an unconditional branch.
579290075Sobrien;; To the basic branch range the PC offset must be added (this is +4).
579390075Sobrien;; So for forward branches we have 
579490075Sobrien;;   (pos_range - pos_base_offs + pc_offs) = (pos_range - 2 + 4).
579590075Sobrien;; And for backward branches we have 
579690075Sobrien;;   (neg_range - neg_base_offs + pc_offs) = (neg_range - (-2 or -4) + 4).
579790075Sobrien;;
579890075Sobrien;; For a 'b'       pos_range = 2046, neg_range = -2048 giving (-2040->2048).
579990075Sobrien;; For a 'b<cond>' pos_range = 254,  neg_range = -256  giving (-250 ->256).
580090075Sobrien
5801132718Skan(define_expand "cbranchsi4"
5802132718Skan  [(set (pc) (if_then_else
5803132718Skan	      (match_operator 0 "arm_comparison_operator"
5804132718Skan	       [(match_operand:SI 1 "s_register_operand" "")
5805132718Skan	        (match_operand:SI 2 "nonmemory_operand" "")])
5806132718Skan	      (label_ref (match_operand 3 "" ""))
5807132718Skan	      (pc)))]
580890075Sobrien  "TARGET_THUMB"
5809132718Skan  "
5810132718Skan  if (thumb_cmpneg_operand (operands[2], SImode))
5811132718Skan    {
5812132718Skan      emit_jump_insn (gen_cbranchsi4_scratch (NULL, operands[1], operands[2],
5813132718Skan					      operands[3], operands[0]));
5814132718Skan      DONE;
5815132718Skan    }
5816132718Skan  if (!thumb_cmp_operand (operands[2], SImode))
5817132718Skan    operands[2] = force_reg (SImode, operands[2]);
5818132718Skan  ")
5819132718Skan
5820132718Skan(define_insn "*cbranchsi4_insn"
5821132718Skan  [(set (pc) (if_then_else
5822132718Skan	      (match_operator 0 "arm_comparison_operator"
5823132718Skan	       [(match_operand:SI 1 "s_register_operand" "l,*h")
5824132718Skan	        (match_operand:SI 2 "thumb_cmp_operand" "lI*h,*r")])
5825132718Skan	      (label_ref (match_operand 3 "" ""))
5826132718Skan	      (pc)))]
5827132718Skan  "TARGET_THUMB"
582890075Sobrien  "*
582990075Sobrien  output_asm_insn (\"cmp\\t%1, %2\", operands);
5830132718Skan
583190075Sobrien  switch (get_attr_length (insn))
583290075Sobrien    {
583390075Sobrien    case 4:  return \"b%d0\\t%l3\";
583490075Sobrien    case 6:  return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
583590075Sobrien    default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
583690075Sobrien    }
583790075Sobrien  "
583890075Sobrien  [(set (attr "far_jump")
583990075Sobrien        (if_then_else
584090075Sobrien	    (eq_attr "length" "8")
584190075Sobrien	    (const_string "yes")
584290075Sobrien            (const_string "no")))
584390075Sobrien   (set (attr "length") 
584490075Sobrien        (if_then_else
584590075Sobrien	    (and (ge (minus (match_dup 3) (pc)) (const_int -250))
584690075Sobrien	         (le (minus (match_dup 3) (pc)) (const_int 256)))
584790075Sobrien	    (const_int 4)
584890075Sobrien	    (if_then_else
584990075Sobrien	        (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
585090075Sobrien		     (le (minus (match_dup 3) (pc)) (const_int 2048)))
585190075Sobrien		(const_int 6)
585290075Sobrien		(const_int 8))))]
585390075Sobrien)
585490075Sobrien
5855132718Skan(define_insn "cbranchsi4_scratch"
5856132718Skan  [(set (pc) (if_then_else
5857132718Skan	      (match_operator 4 "arm_comparison_operator"
5858132718Skan	       [(match_operand:SI 1 "s_register_operand" "l,0")
5859132718Skan	        (match_operand:SI 2 "thumb_cmpneg_operand" "L,J")])
5860132718Skan	      (label_ref (match_operand 3 "" ""))
5861132718Skan	      (pc)))
5862132718Skan   (clobber (match_scratch:SI 0 "=l,l"))]
5863132718Skan  "TARGET_THUMB"
5864132718Skan  "*
5865132718Skan  output_asm_insn (\"add\\t%0, %1, #%n2\", operands);
5866132718Skan
5867132718Skan  switch (get_attr_length (insn))
5868132718Skan    {
5869132718Skan    case 4:  return \"b%d4\\t%l3\";
5870132718Skan    case 6:  return \"b%D4\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
5871132718Skan    default: return \"b%D4\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
5872132718Skan    }
5873132718Skan  "
5874132718Skan  [(set (attr "far_jump")
5875132718Skan        (if_then_else
5876132718Skan	    (eq_attr "length" "8")
5877132718Skan	    (const_string "yes")
5878132718Skan            (const_string "no")))
5879132718Skan   (set (attr "length") 
5880132718Skan        (if_then_else
5881132718Skan	    (and (ge (minus (match_dup 3) (pc)) (const_int -250))
5882132718Skan	         (le (minus (match_dup 3) (pc)) (const_int 256)))
5883132718Skan	    (const_int 4)
5884132718Skan	    (if_then_else
5885132718Skan	        (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
5886132718Skan		     (le (minus (match_dup 3) (pc)) (const_int 2048)))
5887132718Skan		(const_int 6)
5888132718Skan		(const_int 8))))]
5889132718Skan)
5890132718Skan(define_insn "*movsi_cbranchsi4"
5891132718Skan  [(set (pc)
5892132718Skan	(if_then_else
5893132718Skan	 (match_operator 3 "arm_comparison_operator"
5894132718Skan	  [(match_operand:SI 1 "s_register_operand" "0,l,l,l")
5895132718Skan	   (const_int 0)])
5896132718Skan	 (label_ref (match_operand 2 "" ""))
5897132718Skan	 (pc)))
5898132718Skan   (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,l,*h,*m")
5899132718Skan	(match_dup 1))]
5900132718Skan  "TARGET_THUMB"
5901132718Skan  "*{
5902132718Skan  if (which_alternative == 0)
5903132718Skan    output_asm_insn (\"cmp\t%0, #0\", operands);
5904132718Skan  else if (which_alternative == 1)
5905132718Skan    output_asm_insn (\"sub\t%0, %1, #0\", operands);
5906132718Skan  else
5907132718Skan    {
5908132718Skan      output_asm_insn (\"cmp\t%1, #0\", operands);
5909132718Skan      if (which_alternative == 2)
5910132718Skan	output_asm_insn (\"mov\t%0, %1\", operands);
5911132718Skan      else
5912132718Skan	output_asm_insn (\"str\t%1, %0\", operands);
5913132718Skan    }
5914132718Skan  switch (get_attr_length (insn) - ((which_alternative > 1) ? 2 : 0))
5915132718Skan    {
5916132718Skan    case 4:  return \"b%d3\\t%l2\";
5917132718Skan    case 6:  return \"b%D3\\t.LCB%=\;b\\t%l2\\t%@long jump\\n.LCB%=:\";
5918132718Skan    default: return \"b%D3\\t.LCB%=\;bl\\t%l2\\t%@far jump\\n.LCB%=:\";
5919132718Skan    }
5920132718Skan  }"
5921132718Skan  [(set (attr "far_jump")
5922132718Skan        (if_then_else
5923132718Skan	    (ior (and (gt (symbol_ref ("which_alternative"))
5924132718Skan	                  (const_int 1))
5925132718Skan		      (eq_attr "length" "8"))
5926132718Skan		 (eq_attr "length" "10"))
5927132718Skan	    (const_string "yes")
5928132718Skan            (const_string "no")))
5929132718Skan   (set (attr "length")
5930132718Skan     (if_then_else
5931132718Skan       (le (symbol_ref ("which_alternative"))
5932132718Skan		       (const_int 1))
5933132718Skan       (if_then_else
5934132718Skan	 (and (ge (minus (match_dup 2) (pc)) (const_int -250))
5935132718Skan	      (le (minus (match_dup 2) (pc)) (const_int 256)))
5936132718Skan	 (const_int 4)
5937132718Skan	 (if_then_else
5938132718Skan	   (and (ge (minus (match_dup 2) (pc)) (const_int -2040))
5939132718Skan		(le (minus (match_dup 2) (pc)) (const_int 2048)))
5940132718Skan	   (const_int 6)
5941132718Skan	   (const_int 8)))
5942132718Skan       (if_then_else
5943132718Skan	 (and (ge (minus (match_dup 2) (pc)) (const_int -248))
5944132718Skan	      (le (minus (match_dup 2) (pc)) (const_int 256)))
5945132718Skan	 (const_int 6)
5946132718Skan	 (if_then_else
5947132718Skan	   (and (ge (minus (match_dup 2) (pc)) (const_int -2038))
5948132718Skan		(le (minus (match_dup 2) (pc)) (const_int 2048)))
5949132718Skan	   (const_int 8)
5950132718Skan	   (const_int 10)))))]
5951132718Skan)
5952132718Skan
595390075Sobrien(define_insn "*negated_cbranchsi4"
595490075Sobrien  [(set (pc)
595590075Sobrien	(if_then_else
5956169689Skan	 (match_operator 0 "equality_operator"
5957132718Skan	  [(match_operand:SI 1 "s_register_operand" "l")
5958132718Skan	   (neg:SI (match_operand:SI 2 "s_register_operand" "l"))])
5959132718Skan	 (label_ref (match_operand 3 "" ""))
596090075Sobrien	 (pc)))]
596190075Sobrien  "TARGET_THUMB"
596290075Sobrien  "*
596390075Sobrien  output_asm_insn (\"cmn\\t%1, %2\", operands);
596490075Sobrien  switch (get_attr_length (insn))
596590075Sobrien    {
596690075Sobrien    case 4:  return \"b%d0\\t%l3\";
596790075Sobrien    case 6:  return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
596890075Sobrien    default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
596990075Sobrien    }
597090075Sobrien  "
597190075Sobrien  [(set (attr "far_jump")
597290075Sobrien        (if_then_else
597390075Sobrien	    (eq_attr "length" "8")
597490075Sobrien	    (const_string "yes")
597590075Sobrien            (const_string "no")))
597690075Sobrien   (set (attr "length") 
597790075Sobrien        (if_then_else
597890075Sobrien	    (and (ge (minus (match_dup 3) (pc)) (const_int -250))
597990075Sobrien	         (le (minus (match_dup 3) (pc)) (const_int 256)))
598090075Sobrien	    (const_int 4)
598190075Sobrien	    (if_then_else
598290075Sobrien	        (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
598390075Sobrien		     (le (minus (match_dup 3) (pc)) (const_int 2048)))
598490075Sobrien		(const_int 6)
598590075Sobrien		(const_int 8))))]
598690075Sobrien)
598790075Sobrien
5988132718Skan(define_insn "*tbit_cbranch"
5989132718Skan  [(set (pc)
5990132718Skan	(if_then_else
5991132718Skan	 (match_operator 0 "equality_operator"
5992132718Skan	  [(zero_extract:SI (match_operand:SI 1 "s_register_operand" "l")
5993132718Skan			    (const_int 1)
5994132718Skan			    (match_operand:SI 2 "const_int_operand" "i"))
5995132718Skan	   (const_int 0)])
5996132718Skan	 (label_ref (match_operand 3 "" ""))
5997132718Skan	 (pc)))
5998132718Skan   (clobber (match_scratch:SI 4 "=l"))]
5999132718Skan  "TARGET_THUMB"
6000132718Skan  "*
6001132718Skan  {
6002132718Skan  rtx op[3];
6003132718Skan  op[0] = operands[4];
6004132718Skan  op[1] = operands[1];
6005132718Skan  op[2] = GEN_INT (32 - 1 - INTVAL (operands[2]));
600690075Sobrien
6007132718Skan  output_asm_insn (\"lsl\\t%0, %1, %2\", op);
6008132718Skan  switch (get_attr_length (insn))
6009132718Skan    {
6010132718Skan    case 4:  return \"b%d0\\t%l3\";
6011132718Skan    case 6:  return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
6012132718Skan    default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
6013132718Skan    }
6014132718Skan  }"
6015132718Skan  [(set (attr "far_jump")
6016132718Skan        (if_then_else
6017132718Skan	    (eq_attr "length" "8")
6018132718Skan	    (const_string "yes")
6019132718Skan            (const_string "no")))
6020132718Skan   (set (attr "length") 
6021132718Skan        (if_then_else
6022132718Skan	    (and (ge (minus (match_dup 3) (pc)) (const_int -250))
6023132718Skan	         (le (minus (match_dup 3) (pc)) (const_int 256)))
6024132718Skan	    (const_int 4)
6025132718Skan	    (if_then_else
6026132718Skan	        (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
6027132718Skan		     (le (minus (match_dup 3) (pc)) (const_int 2048)))
6028132718Skan		(const_int 6)
6029132718Skan		(const_int 8))))]
6030132718Skan)
6031132718Skan  
6032169689Skan(define_insn "*tlobits_cbranch"
6033169689Skan  [(set (pc)
6034169689Skan	(if_then_else
6035169689Skan	 (match_operator 0 "equality_operator"
6036169689Skan	  [(zero_extract:SI (match_operand:SI 1 "s_register_operand" "l")
6037169689Skan			    (match_operand:SI 2 "const_int_operand" "i")
6038169689Skan			    (const_int 0))
6039169689Skan	   (const_int 0)])
6040169689Skan	 (label_ref (match_operand 3 "" ""))
6041169689Skan	 (pc)))
6042169689Skan   (clobber (match_scratch:SI 4 "=l"))]
6043169689Skan  "TARGET_THUMB"
6044169689Skan  "*
6045169689Skan  {
6046169689Skan  rtx op[3];
6047169689Skan  op[0] = operands[4];
6048169689Skan  op[1] = operands[1];
6049169689Skan  op[2] = GEN_INT (32 - INTVAL (operands[2]));
6050169689Skan
6051169689Skan  output_asm_insn (\"lsl\\t%0, %1, %2\", op);
6052169689Skan  switch (get_attr_length (insn))
6053169689Skan    {
6054169689Skan    case 4:  return \"b%d0\\t%l3\";
6055169689Skan    case 6:  return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
6056169689Skan    default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
6057169689Skan    }
6058169689Skan  }"
6059169689Skan  [(set (attr "far_jump")
6060169689Skan        (if_then_else
6061169689Skan	    (eq_attr "length" "8")
6062169689Skan	    (const_string "yes")
6063169689Skan            (const_string "no")))
6064169689Skan   (set (attr "length") 
6065169689Skan        (if_then_else
6066169689Skan	    (and (ge (minus (match_dup 3) (pc)) (const_int -250))
6067169689Skan	         (le (minus (match_dup 3) (pc)) (const_int 256)))
6068169689Skan	    (const_int 4)
6069169689Skan	    (if_then_else
6070169689Skan	        (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
6071169689Skan		     (le (minus (match_dup 3) (pc)) (const_int 2048)))
6072169689Skan		(const_int 6)
6073169689Skan		(const_int 8))))]
6074169689Skan)
6075169689Skan  
6076132718Skan(define_insn "*tstsi3_cbranch"
6077132718Skan  [(set (pc)
6078132718Skan	(if_then_else
6079132718Skan	 (match_operator 3 "equality_operator"
6080132718Skan	  [(and:SI (match_operand:SI 0 "s_register_operand" "%l")
6081132718Skan		   (match_operand:SI 1 "s_register_operand" "l"))
6082132718Skan	   (const_int 0)])
6083132718Skan	 (label_ref (match_operand 2 "" ""))
6084132718Skan	 (pc)))]
6085132718Skan  "TARGET_THUMB"
6086132718Skan  "*
6087132718Skan  {
6088132718Skan  output_asm_insn (\"tst\\t%0, %1\", operands);
6089132718Skan  switch (get_attr_length (insn))
6090132718Skan    {
6091132718Skan    case 4:  return \"b%d3\\t%l2\";
6092132718Skan    case 6:  return \"b%D3\\t.LCB%=\;b\\t%l2\\t%@long jump\\n.LCB%=:\";
6093132718Skan    default: return \"b%D3\\t.LCB%=\;bl\\t%l2\\t%@far jump\\n.LCB%=:\";
6094132718Skan    }
6095132718Skan  }"
6096132718Skan  [(set (attr "far_jump")
6097132718Skan        (if_then_else
6098132718Skan	    (eq_attr "length" "8")
6099132718Skan	    (const_string "yes")
6100132718Skan            (const_string "no")))
6101132718Skan   (set (attr "length") 
6102132718Skan        (if_then_else
6103132718Skan	    (and (ge (minus (match_dup 2) (pc)) (const_int -250))
6104132718Skan	         (le (minus (match_dup 2) (pc)) (const_int 256)))
6105132718Skan	    (const_int 4)
6106132718Skan	    (if_then_else
6107132718Skan	        (and (ge (minus (match_dup 2) (pc)) (const_int -2040))
6108132718Skan		     (le (minus (match_dup 2) (pc)) (const_int 2048)))
6109132718Skan		(const_int 6)
6110132718Skan		(const_int 8))))]
6111132718Skan)
6112132718Skan  
6113132718Skan(define_insn "*andsi3_cbranch"
6114132718Skan  [(set (pc)
6115132718Skan	(if_then_else
6116132718Skan	 (match_operator 5 "equality_operator"
6117132718Skan	  [(and:SI (match_operand:SI 2 "s_register_operand" "%0,1,1,1")
6118132718Skan		   (match_operand:SI 3 "s_register_operand" "l,l,l,l"))
6119132718Skan	   (const_int 0)])
6120132718Skan	 (label_ref (match_operand 4 "" ""))
6121132718Skan	 (pc)))
6122132718Skan   (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,*?h,*?m,*?m")
6123132718Skan	(and:SI (match_dup 2) (match_dup 3)))
6124132718Skan   (clobber (match_scratch:SI 1 "=X,l,&l,&l"))]
6125132718Skan  "TARGET_THUMB"
6126132718Skan  "*
6127132718Skan  {
6128132718Skan  if (which_alternative == 0)
6129132718Skan    output_asm_insn (\"and\\t%0, %3\", operands);
6130132718Skan  else if (which_alternative == 1)
6131132718Skan    {
6132132718Skan      output_asm_insn (\"and\\t%1, %3\", operands);
6133132718Skan      output_asm_insn (\"mov\\t%0, %1\", operands);
6134132718Skan    }
6135132718Skan  else
6136132718Skan    {
6137132718Skan      output_asm_insn (\"and\\t%1, %3\", operands);
6138132718Skan      output_asm_insn (\"str\\t%1, %0\", operands);
6139132718Skan    }
6140132718Skan
6141132718Skan  switch (get_attr_length (insn) - (which_alternative ? 2 : 0))
6142132718Skan    {
6143132718Skan    case 4:  return \"b%d5\\t%l4\";
6144132718Skan    case 6:  return \"b%D5\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\";
6145132718Skan    default: return \"b%D5\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\";
6146132718Skan    }
6147132718Skan  }"
6148132718Skan  [(set (attr "far_jump")
6149132718Skan        (if_then_else
6150132718Skan	    (ior (and (eq (symbol_ref ("which_alternative"))
6151132718Skan	                  (const_int 0))
6152132718Skan		      (eq_attr "length" "8"))
6153132718Skan		 (eq_attr "length" "10"))
6154132718Skan	    (const_string "yes")
6155132718Skan            (const_string "no")))
6156132718Skan   (set (attr "length")
6157132718Skan     (if_then_else
6158132718Skan       (eq (symbol_ref ("which_alternative"))
6159132718Skan		       (const_int 0))
6160132718Skan       (if_then_else
6161132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -250))
6162132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
6163132718Skan	 (const_int 4)
6164132718Skan	 (if_then_else
6165132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2040))
6166132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
6167132718Skan	   (const_int 6)
6168132718Skan	   (const_int 8)))
6169132718Skan       (if_then_else
6170132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -248))
6171132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
6172132718Skan	 (const_int 6)
6173132718Skan	 (if_then_else
6174132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
6175132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
6176132718Skan	   (const_int 8)
6177132718Skan	   (const_int 10)))))]
6178132718Skan)
6179132718Skan
6180132718Skan(define_insn "*orrsi3_cbranch_scratch"
6181132718Skan  [(set (pc)
6182132718Skan	(if_then_else
6183132718Skan	 (match_operator 4 "equality_operator"
6184132718Skan	  [(ior:SI (match_operand:SI 1 "s_register_operand" "%0")
6185132718Skan		   (match_operand:SI 2 "s_register_operand" "l"))
6186132718Skan	   (const_int 0)])
6187132718Skan	 (label_ref (match_operand 3 "" ""))
6188132718Skan	 (pc)))
6189132718Skan   (clobber (match_scratch:SI 0 "=l"))]
6190132718Skan  "TARGET_THUMB"
6191132718Skan  "*
6192132718Skan  {
6193132718Skan  output_asm_insn (\"orr\\t%0, %2\", operands);
6194132718Skan  switch (get_attr_length (insn))
6195132718Skan    {
6196132718Skan    case 4:  return \"b%d4\\t%l3\";
6197132718Skan    case 6:  return \"b%D4\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
6198132718Skan    default: return \"b%D4\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
6199132718Skan    }
6200132718Skan  }"
6201132718Skan  [(set (attr "far_jump")
6202132718Skan        (if_then_else
6203132718Skan	    (eq_attr "length" "8")
6204132718Skan	    (const_string "yes")
6205132718Skan            (const_string "no")))
6206132718Skan   (set (attr "length") 
6207132718Skan        (if_then_else
6208132718Skan	    (and (ge (minus (match_dup 3) (pc)) (const_int -250))
6209132718Skan	         (le (minus (match_dup 3) (pc)) (const_int 256)))
6210132718Skan	    (const_int 4)
6211132718Skan	    (if_then_else
6212132718Skan	        (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
6213132718Skan		     (le (minus (match_dup 3) (pc)) (const_int 2048)))
6214132718Skan		(const_int 6)
6215132718Skan		(const_int 8))))]
6216132718Skan)
6217132718Skan  
6218132718Skan(define_insn "*orrsi3_cbranch"
6219132718Skan  [(set (pc)
6220132718Skan	(if_then_else
6221132718Skan	 (match_operator 5 "equality_operator"
6222132718Skan	  [(ior:SI (match_operand:SI 2 "s_register_operand" "%0,1,1,1")
6223132718Skan		   (match_operand:SI 3 "s_register_operand" "l,l,l,l"))
6224132718Skan	   (const_int 0)])
6225132718Skan	 (label_ref (match_operand 4 "" ""))
6226132718Skan	 (pc)))
6227132718Skan   (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,*?h,*?m,*?m")
6228132718Skan	(ior:SI (match_dup 2) (match_dup 3)))
6229132718Skan   (clobber (match_scratch:SI 1 "=X,l,&l,&l"))]
6230132718Skan  "TARGET_THUMB"
6231132718Skan  "*
6232132718Skan  {
6233132718Skan  if (which_alternative == 0)
6234132718Skan    output_asm_insn (\"orr\\t%0, %3\", operands);
6235132718Skan  else if (which_alternative == 1)
6236132718Skan    {
6237132718Skan      output_asm_insn (\"orr\\t%1, %3\", operands);
6238132718Skan      output_asm_insn (\"mov\\t%0, %1\", operands);
6239132718Skan    }
6240132718Skan  else
6241132718Skan    {
6242132718Skan      output_asm_insn (\"orr\\t%1, %3\", operands);
6243132718Skan      output_asm_insn (\"str\\t%1, %0\", operands);
6244132718Skan    }
6245132718Skan
6246132718Skan  switch (get_attr_length (insn) - (which_alternative ? 2 : 0))
6247132718Skan    {
6248132718Skan    case 4:  return \"b%d5\\t%l4\";
6249132718Skan    case 6:  return \"b%D5\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\";
6250132718Skan    default: return \"b%D5\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\";
6251132718Skan    }
6252132718Skan  }"
6253132718Skan  [(set (attr "far_jump")
6254132718Skan        (if_then_else
6255132718Skan	    (ior (and (eq (symbol_ref ("which_alternative"))
6256132718Skan	                  (const_int 0))
6257132718Skan		      (eq_attr "length" "8"))
6258132718Skan		 (eq_attr "length" "10"))
6259132718Skan	    (const_string "yes")
6260132718Skan            (const_string "no")))
6261132718Skan   (set (attr "length")
6262132718Skan     (if_then_else
6263132718Skan       (eq (symbol_ref ("which_alternative"))
6264132718Skan		       (const_int 0))
6265132718Skan       (if_then_else
6266132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -250))
6267132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
6268132718Skan	 (const_int 4)
6269132718Skan	 (if_then_else
6270132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2040))
6271132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
6272132718Skan	   (const_int 6)
6273132718Skan	   (const_int 8)))
6274132718Skan       (if_then_else
6275132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -248))
6276132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
6277132718Skan	 (const_int 6)
6278132718Skan	 (if_then_else
6279132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
6280132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
6281132718Skan	   (const_int 8)
6282132718Skan	   (const_int 10)))))]
6283132718Skan)
6284132718Skan
6285132718Skan(define_insn "*xorsi3_cbranch_scratch"
6286132718Skan  [(set (pc)
6287132718Skan	(if_then_else
6288132718Skan	 (match_operator 4 "equality_operator"
6289132718Skan	  [(xor:SI (match_operand:SI 1 "s_register_operand" "%0")
6290132718Skan		   (match_operand:SI 2 "s_register_operand" "l"))
6291132718Skan	   (const_int 0)])
6292132718Skan	 (label_ref (match_operand 3 "" ""))
6293132718Skan	 (pc)))
6294132718Skan   (clobber (match_scratch:SI 0 "=l"))]
6295132718Skan  "TARGET_THUMB"
6296132718Skan  "*
6297132718Skan  {
6298132718Skan  output_asm_insn (\"eor\\t%0, %2\", operands);
6299132718Skan  switch (get_attr_length (insn))
6300132718Skan    {
6301132718Skan    case 4:  return \"b%d4\\t%l3\";
6302132718Skan    case 6:  return \"b%D4\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
6303132718Skan    default: return \"b%D4\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
6304132718Skan    }
6305132718Skan  }"
6306132718Skan  [(set (attr "far_jump")
6307132718Skan        (if_then_else
6308132718Skan	    (eq_attr "length" "8")
6309132718Skan	    (const_string "yes")
6310132718Skan            (const_string "no")))
6311132718Skan   (set (attr "length") 
6312132718Skan        (if_then_else
6313132718Skan	    (and (ge (minus (match_dup 3) (pc)) (const_int -250))
6314132718Skan	         (le (minus (match_dup 3) (pc)) (const_int 256)))
6315132718Skan	    (const_int 4)
6316132718Skan	    (if_then_else
6317132718Skan	        (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
6318132718Skan		     (le (minus (match_dup 3) (pc)) (const_int 2048)))
6319132718Skan		(const_int 6)
6320132718Skan		(const_int 8))))]
6321132718Skan)
6322132718Skan  
6323132718Skan(define_insn "*xorsi3_cbranch"
6324132718Skan  [(set (pc)
6325132718Skan	(if_then_else
6326132718Skan	 (match_operator 5 "equality_operator"
6327132718Skan	  [(xor:SI (match_operand:SI 2 "s_register_operand" "%0,1,1,1")
6328132718Skan		   (match_operand:SI 3 "s_register_operand" "l,l,l,l"))
6329132718Skan	   (const_int 0)])
6330132718Skan	 (label_ref (match_operand 4 "" ""))
6331132718Skan	 (pc)))
6332132718Skan   (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,*?h,*?m,*?m")
6333132718Skan	(xor:SI (match_dup 2) (match_dup 3)))
6334132718Skan   (clobber (match_scratch:SI 1 "=X,l,&l,&l"))]
6335132718Skan  "TARGET_THUMB"
6336132718Skan  "*
6337132718Skan  {
6338132718Skan  if (which_alternative == 0)
6339132718Skan    output_asm_insn (\"eor\\t%0, %3\", operands);
6340132718Skan  else if (which_alternative == 1)
6341132718Skan    {
6342132718Skan      output_asm_insn (\"eor\\t%1, %3\", operands);
6343132718Skan      output_asm_insn (\"mov\\t%0, %1\", operands);
6344132718Skan    }
6345132718Skan  else
6346132718Skan    {
6347132718Skan      output_asm_insn (\"eor\\t%1, %3\", operands);
6348132718Skan      output_asm_insn (\"str\\t%1, %0\", operands);
6349132718Skan    }
6350132718Skan
6351132718Skan  switch (get_attr_length (insn) - (which_alternative ? 2 : 0))
6352132718Skan    {
6353132718Skan    case 4:  return \"b%d5\\t%l4\";
6354132718Skan    case 6:  return \"b%D5\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\";
6355132718Skan    default: return \"b%D5\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\";
6356132718Skan    }
6357132718Skan  }"
6358132718Skan  [(set (attr "far_jump")
6359132718Skan        (if_then_else
6360132718Skan	    (ior (and (eq (symbol_ref ("which_alternative"))
6361132718Skan	                  (const_int 0))
6362132718Skan		      (eq_attr "length" "8"))
6363132718Skan		 (eq_attr "length" "10"))
6364132718Skan	    (const_string "yes")
6365132718Skan            (const_string "no")))
6366132718Skan   (set (attr "length")
6367132718Skan     (if_then_else
6368132718Skan       (eq (symbol_ref ("which_alternative"))
6369132718Skan		       (const_int 0))
6370132718Skan       (if_then_else
6371132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -250))
6372132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
6373132718Skan	 (const_int 4)
6374132718Skan	 (if_then_else
6375132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2040))
6376132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
6377132718Skan	   (const_int 6)
6378132718Skan	   (const_int 8)))
6379132718Skan       (if_then_else
6380132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -248))
6381132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
6382132718Skan	 (const_int 6)
6383132718Skan	 (if_then_else
6384132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
6385132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
6386132718Skan	   (const_int 8)
6387132718Skan	   (const_int 10)))))]
6388132718Skan)
6389132718Skan
6390132718Skan(define_insn "*bicsi3_cbranch_scratch"
6391132718Skan  [(set (pc)
6392132718Skan	(if_then_else
6393132718Skan	 (match_operator 4 "equality_operator"
6394132718Skan	  [(and:SI (not:SI (match_operand:SI 2 "s_register_operand" "l"))
6395132718Skan		   (match_operand:SI 1 "s_register_operand" "0"))
6396132718Skan	   (const_int 0)])
6397132718Skan	 (label_ref (match_operand 3 "" ""))
6398132718Skan	 (pc)))
6399132718Skan   (clobber (match_scratch:SI 0 "=l"))]
6400132718Skan  "TARGET_THUMB"
6401132718Skan  "*
6402132718Skan  {
6403132718Skan  output_asm_insn (\"bic\\t%0, %2\", operands);
6404132718Skan  switch (get_attr_length (insn))
6405132718Skan    {
6406132718Skan    case 4:  return \"b%d4\\t%l3\";
6407132718Skan    case 6:  return \"b%D4\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
6408132718Skan    default: return \"b%D4\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
6409132718Skan    }
6410132718Skan  }"
6411132718Skan  [(set (attr "far_jump")
6412132718Skan        (if_then_else
6413132718Skan	    (eq_attr "length" "8")
6414132718Skan	    (const_string "yes")
6415132718Skan            (const_string "no")))
6416132718Skan   (set (attr "length") 
6417132718Skan        (if_then_else
6418132718Skan	    (and (ge (minus (match_dup 3) (pc)) (const_int -250))
6419132718Skan	         (le (minus (match_dup 3) (pc)) (const_int 256)))
6420132718Skan	    (const_int 4)
6421132718Skan	    (if_then_else
6422132718Skan	        (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
6423132718Skan		     (le (minus (match_dup 3) (pc)) (const_int 2048)))
6424132718Skan		(const_int 6)
6425132718Skan		(const_int 8))))]
6426132718Skan)
6427132718Skan  
6428132718Skan(define_insn "*bicsi3_cbranch"
6429132718Skan  [(set (pc)
6430132718Skan	(if_then_else
6431132718Skan	 (match_operator 5 "equality_operator"
6432146895Skan	  [(and:SI (not:SI (match_operand:SI 3 "s_register_operand" "l,l,l,l,l"))
6433146895Skan		   (match_operand:SI 2 "s_register_operand" "0,1,1,1,1"))
6434132718Skan	   (const_int 0)])
6435132718Skan	 (label_ref (match_operand 4 "" ""))
6436132718Skan	 (pc)))
6437146895Skan   (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=!l,l,*?h,*?m,*?m")
6438132718Skan	(and:SI (not:SI (match_dup 3)) (match_dup 2)))
6439146895Skan   (clobber (match_scratch:SI 1 "=X,l,l,&l,&l"))]
6440132718Skan  "TARGET_THUMB"
6441132718Skan  "*
6442132718Skan  {
6443132718Skan  if (which_alternative == 0)
6444132718Skan    output_asm_insn (\"bic\\t%0, %3\", operands);
6445146895Skan  else if (which_alternative <= 2)
6446132718Skan    {
6447132718Skan      output_asm_insn (\"bic\\t%1, %3\", operands);
6448146895Skan      /* It's ok if OP0 is a lo-reg, even though the mov will set the
6449146895Skan	 conditions again, since we're only testing for equality.  */
6450132718Skan      output_asm_insn (\"mov\\t%0, %1\", operands);
6451132718Skan    }
6452132718Skan  else
6453132718Skan    {
6454132718Skan      output_asm_insn (\"bic\\t%1, %3\", operands);
6455132718Skan      output_asm_insn (\"str\\t%1, %0\", operands);
6456132718Skan    }
6457132718Skan
6458132718Skan  switch (get_attr_length (insn) - (which_alternative ? 2 : 0))
6459132718Skan    {
6460132718Skan    case 4:  return \"b%d5\\t%l4\";
6461132718Skan    case 6:  return \"b%D5\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\";
6462132718Skan    default: return \"b%D5\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\";
6463132718Skan    }
6464132718Skan  }"
6465132718Skan  [(set (attr "far_jump")
6466132718Skan        (if_then_else
6467132718Skan	    (ior (and (eq (symbol_ref ("which_alternative"))
6468132718Skan	                  (const_int 0))
6469132718Skan		      (eq_attr "length" "8"))
6470132718Skan		 (eq_attr "length" "10"))
6471132718Skan	    (const_string "yes")
6472132718Skan            (const_string "no")))
6473132718Skan   (set (attr "length")
6474132718Skan     (if_then_else
6475132718Skan       (eq (symbol_ref ("which_alternative"))
6476132718Skan		       (const_int 0))
6477132718Skan       (if_then_else
6478132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -250))
6479132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
6480132718Skan	 (const_int 4)
6481132718Skan	 (if_then_else
6482132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2040))
6483132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
6484132718Skan	   (const_int 6)
6485132718Skan	   (const_int 8)))
6486132718Skan       (if_then_else
6487132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -248))
6488132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
6489132718Skan	 (const_int 6)
6490132718Skan	 (if_then_else
6491132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
6492132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
6493132718Skan	   (const_int 8)
6494132718Skan	   (const_int 10)))))]
6495132718Skan)
6496132718Skan
6497132718Skan(define_insn "*cbranchne_decr1"
6498132718Skan  [(set (pc)
6499132718Skan	(if_then_else (match_operator 3 "equality_operator"
6500132718Skan		       [(match_operand:SI 2 "s_register_operand" "l,l,1,l")
6501132718Skan		        (const_int 0)])
6502132718Skan		      (label_ref (match_operand 4 "" ""))
6503132718Skan		      (pc)))
6504132718Skan   (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,*?h,*?m,*?m")
6505132718Skan	(plus:SI (match_dup 2) (const_int -1)))
6506132718Skan   (clobber (match_scratch:SI 1 "=X,l,&l,&l"))]
6507132718Skan  "TARGET_THUMB"
6508132718Skan  "*
6509132718Skan   {
6510132718Skan     rtx cond[2];
6511132718Skan     cond[0] = gen_rtx_fmt_ee ((GET_CODE (operands[3]) == NE
6512132718Skan				? GEU : LTU),
6513132718Skan			       VOIDmode, operands[2], const1_rtx);
6514132718Skan     cond[1] = operands[4];
6515132718Skan
6516132718Skan     if (which_alternative == 0)
6517132718Skan       output_asm_insn (\"sub\\t%0, %2, #1\", operands);
6518132718Skan     else if (which_alternative == 1)
6519132718Skan       {
6520132718Skan	 /* We must provide an alternative for a hi reg because reload 
6521132718Skan	    cannot handle output reloads on a jump instruction, but we
6522132718Skan	    can't subtract into that.  Fortunately a mov from lo to hi
6523132718Skan	    does not clobber the condition codes.  */
6524132718Skan	 output_asm_insn (\"sub\\t%1, %2, #1\", operands);
6525132718Skan	 output_asm_insn (\"mov\\t%0, %1\", operands);
6526132718Skan       }
6527132718Skan     else
6528132718Skan       {
6529132718Skan	 /* Similarly, but the target is memory.  */
6530132718Skan	 output_asm_insn (\"sub\\t%1, %2, #1\", operands);
6531132718Skan	 output_asm_insn (\"str\\t%1, %0\", operands);
6532132718Skan       }
6533132718Skan
6534132718Skan     switch (get_attr_length (insn) - (which_alternative ? 2 : 0))
6535132718Skan       {
6536132718Skan	 case 4:
6537132718Skan	   output_asm_insn (\"b%d0\\t%l1\", cond);
6538132718Skan	   return \"\";
6539132718Skan	 case 6:
6540132718Skan	   output_asm_insn (\"b%D0\\t.LCB%=\", cond);
6541132718Skan	   return \"b\\t%l4\\t%@long jump\\n.LCB%=:\";
6542132718Skan	 default:
6543132718Skan	   output_asm_insn (\"b%D0\\t.LCB%=\", cond);
6544132718Skan	   return \"bl\\t%l4\\t%@far jump\\n.LCB%=:\";
6545132718Skan       }
6546132718Skan   }
6547132718Skan  "
6548132718Skan  [(set (attr "far_jump")
6549132718Skan        (if_then_else
6550132718Skan	    (ior (and (eq (symbol_ref ("which_alternative"))
6551132718Skan	                  (const_int 0))
6552132718Skan		      (eq_attr "length" "8"))
6553132718Skan		 (eq_attr "length" "10"))
6554132718Skan	    (const_string "yes")
6555132718Skan            (const_string "no")))
6556132718Skan   (set_attr_alternative "length"
6557132718Skan      [
6558132718Skan       ;; Alternative 0
6559132718Skan       (if_then_else
6560132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -250))
6561132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
6562132718Skan	 (const_int 4)
6563132718Skan	 (if_then_else
6564132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2040))
6565132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
6566132718Skan	   (const_int 6)
6567132718Skan	   (const_int 8)))
6568132718Skan       ;; Alternative 1
6569132718Skan       (if_then_else
6570132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -248))
6571132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
6572132718Skan	 (const_int 6)
6573132718Skan	 (if_then_else
6574132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
6575132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
6576132718Skan	   (const_int 8)
6577132718Skan	   (const_int 10)))
6578132718Skan       ;; Alternative 2
6579132718Skan       (if_then_else
6580132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -248))
6581132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
6582132718Skan	 (const_int 6)
6583132718Skan	 (if_then_else
6584132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
6585132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
6586132718Skan	   (const_int 8)
6587132718Skan	   (const_int 10)))
6588132718Skan       ;; Alternative 3
6589132718Skan       (if_then_else
6590132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -248))
6591132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
6592132718Skan	 (const_int 6)
6593132718Skan	 (if_then_else
6594132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
6595132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
6596132718Skan	   (const_int 8)
6597132718Skan	   (const_int 10)))])]
6598132718Skan)
6599132718Skan
6600132718Skan(define_insn "*addsi3_cbranch"
6601132718Skan  [(set (pc)
6602132718Skan	(if_then_else
6603132718Skan	 (match_operator 4 "comparison_operator"
6604132718Skan	  [(plus:SI
6605132718Skan	    (match_operand:SI 2 "s_register_operand" "%l,0,*0,1,1,1")
6606132718Skan	    (match_operand:SI 3 "reg_or_int_operand" "lL,IJ,*r,lIJ,lIJ,lIJ"))
6607132718Skan	   (const_int 0)])
6608132718Skan	 (label_ref (match_operand 5 "" ""))
6609132718Skan	 (pc)))
6610132718Skan   (set
6611132718Skan    (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,l,*!h,*?h,*?m,*?m")
6612132718Skan    (plus:SI (match_dup 2) (match_dup 3)))
6613132718Skan   (clobber (match_scratch:SI 1 "=X,X,X,l,&l,&l"))]
6614132718Skan  "TARGET_THUMB
6615132718Skan   && (GET_CODE (operands[4]) == EQ
6616132718Skan       || GET_CODE (operands[4]) == NE
6617132718Skan       || GET_CODE (operands[4]) == GE
6618132718Skan       || GET_CODE (operands[4]) == LT)"
6619132718Skan  "*
6620132718Skan   {
6621132718Skan     rtx cond[3];
6622132718Skan
6623132718Skan     
6624132718Skan     cond[0] = (which_alternative < 3) ? operands[0] : operands[1];
6625132718Skan     cond[1] = operands[2];
6626132718Skan     cond[2] = operands[3];
6627132718Skan
6628132718Skan     if (GET_CODE (cond[2]) == CONST_INT && INTVAL (cond[2]) < 0)
6629132718Skan       output_asm_insn (\"sub\\t%0, %1, #%n2\", cond);
6630132718Skan     else
6631132718Skan       output_asm_insn (\"add\\t%0, %1, %2\", cond);
6632132718Skan
6633132718Skan     if (which_alternative >= 3
6634132718Skan	 && which_alternative < 4)
6635132718Skan       output_asm_insn (\"mov\\t%0, %1\", operands);
6636132718Skan     else if (which_alternative >= 4)
6637132718Skan       output_asm_insn (\"str\\t%1, %0\", operands);
6638132718Skan
6639132718Skan     switch (get_attr_length (insn) - ((which_alternative >= 3) ? 2 : 0))
6640132718Skan       {
6641132718Skan	 case 4:
6642132718Skan	   return \"b%d4\\t%l5\";
6643132718Skan	 case 6:
6644132718Skan	   return \"b%D4\\t.LCB%=\;b\\t%l5\\t%@long jump\\n.LCB%=:\";
6645132718Skan	 default:
6646132718Skan	   return \"b%D4\\t.LCB%=\;bl\\t%l5\\t%@far jump\\n.LCB%=:\";
6647132718Skan       }
6648132718Skan   }
6649132718Skan  "
6650132718Skan  [(set (attr "far_jump")
6651132718Skan        (if_then_else
6652132718Skan	    (ior (and (lt (symbol_ref ("which_alternative"))
6653132718Skan	                  (const_int 3))
6654132718Skan		      (eq_attr "length" "8"))
6655132718Skan		 (eq_attr "length" "10"))
6656132718Skan	    (const_string "yes")
6657132718Skan            (const_string "no")))
6658132718Skan   (set (attr "length")
6659132718Skan     (if_then_else
6660132718Skan       (lt (symbol_ref ("which_alternative"))
6661132718Skan		       (const_int 3))
6662132718Skan       (if_then_else
6663132718Skan	 (and (ge (minus (match_dup 5) (pc)) (const_int -250))
6664132718Skan	      (le (minus (match_dup 5) (pc)) (const_int 256)))
6665132718Skan	 (const_int 4)
6666132718Skan	 (if_then_else
6667132718Skan	   (and (ge (minus (match_dup 5) (pc)) (const_int -2040))
6668132718Skan		(le (minus (match_dup 5) (pc)) (const_int 2048)))
6669132718Skan	   (const_int 6)
6670132718Skan	   (const_int 8)))
6671132718Skan       (if_then_else
6672132718Skan	 (and (ge (minus (match_dup 5) (pc)) (const_int -248))
6673132718Skan	      (le (minus (match_dup 5) (pc)) (const_int 256)))
6674132718Skan	 (const_int 6)
6675132718Skan	 (if_then_else
6676132718Skan	   (and (ge (minus (match_dup 5) (pc)) (const_int -2038))
6677132718Skan		(le (minus (match_dup 5) (pc)) (const_int 2048)))
6678132718Skan	   (const_int 8)
6679132718Skan	   (const_int 10)))))]
6680132718Skan)
6681132718Skan
6682132718Skan(define_insn "*addsi3_cbranch_scratch"
6683132718Skan  [(set (pc)
6684132718Skan	(if_then_else
6685132718Skan	 (match_operator 3 "comparison_operator"
6686132718Skan	  [(plus:SI
6687132718Skan	    (match_operand:SI 1 "s_register_operand" "%l,l,l,0")
6688169689Skan	    (match_operand:SI 2 "reg_or_int_operand" "J,l,L,IJ"))
6689132718Skan	   (const_int 0)])
6690132718Skan	 (label_ref (match_operand 4 "" ""))
6691132718Skan	 (pc)))
6692132718Skan   (clobber (match_scratch:SI 0 "=X,X,l,l"))]
6693132718Skan  "TARGET_THUMB
6694132718Skan   && (GET_CODE (operands[3]) == EQ
6695132718Skan       || GET_CODE (operands[3]) == NE
6696132718Skan       || GET_CODE (operands[3]) == GE
6697132718Skan       || GET_CODE (operands[3]) == LT)"
6698132718Skan  "*
6699132718Skan   {
6700132718Skan     switch (which_alternative)
6701132718Skan       {
6702132718Skan       case 0:
6703132718Skan	 output_asm_insn (\"cmp\t%1, #%n2\", operands);
6704132718Skan	 break;
6705132718Skan       case 1:
6706132718Skan	 output_asm_insn (\"cmn\t%1, %2\", operands);
6707132718Skan	 break;
6708146895Skan       case 2:
6709169689Skan	 if (INTVAL (operands[2]) < 0)
6710169689Skan	   output_asm_insn (\"sub\t%0, %1, %2\", operands);
6711169689Skan	 else
6712169689Skan	   output_asm_insn (\"add\t%0, %1, %2\", operands);
6713132718Skan	 break;
6714146895Skan       case 3:
6715169689Skan	 if (INTVAL (operands[2]) < 0)
6716169689Skan	   output_asm_insn (\"sub\t%0, %0, %2\", operands);
6717169689Skan	 else
6718169689Skan	   output_asm_insn (\"add\t%0, %0, %2\", operands);
6719132718Skan	 break;
6720132718Skan       }
6721132718Skan
6722132718Skan     switch (get_attr_length (insn))
6723132718Skan       {
6724132718Skan	 case 4:
6725132718Skan	   return \"b%d3\\t%l4\";
6726132718Skan	 case 6:
6727132718Skan	   return \"b%D3\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\";
6728132718Skan	 default:
6729132718Skan	   return \"b%D3\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\";
6730132718Skan       }
6731132718Skan   }
6732132718Skan  "
6733132718Skan  [(set (attr "far_jump")
6734132718Skan        (if_then_else
6735132718Skan	    (eq_attr "length" "8")
6736132718Skan	    (const_string "yes")
6737132718Skan            (const_string "no")))
6738132718Skan   (set (attr "length")
6739132718Skan       (if_then_else
6740132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -250))
6741132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
6742132718Skan	 (const_int 4)
6743132718Skan	 (if_then_else
6744132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2040))
6745132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
6746132718Skan	   (const_int 6)
6747132718Skan	   (const_int 8))))]
6748132718Skan)
6749132718Skan
6750132718Skan(define_insn "*subsi3_cbranch"
6751132718Skan  [(set (pc)
6752132718Skan	(if_then_else
6753132718Skan	 (match_operator 4 "comparison_operator"
6754132718Skan	  [(minus:SI
6755132718Skan	    (match_operand:SI 2 "s_register_operand" "l,l,1,l")
6756132718Skan	    (match_operand:SI 3 "s_register_operand" "l,l,l,l"))
6757132718Skan	   (const_int 0)])
6758132718Skan	 (label_ref (match_operand 5 "" ""))
6759132718Skan	 (pc)))
6760132718Skan   (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,*?h,*?m,*?m")
6761132718Skan	(minus:SI (match_dup 2) (match_dup 3)))
6762132718Skan   (clobber (match_scratch:SI 1 "=X,l,&l,&l"))]
6763132718Skan  "TARGET_THUMB
6764132718Skan   && (GET_CODE (operands[4]) == EQ
6765132718Skan       || GET_CODE (operands[4]) == NE
6766132718Skan       || GET_CODE (operands[4]) == GE
6767132718Skan       || GET_CODE (operands[4]) == LT)"
6768132718Skan  "*
6769132718Skan   {
6770132718Skan     if (which_alternative == 0)
6771132718Skan       output_asm_insn (\"sub\\t%0, %2, %3\", operands);
6772132718Skan     else if (which_alternative == 1)
6773132718Skan       {
6774132718Skan	 /* We must provide an alternative for a hi reg because reload 
6775132718Skan	    cannot handle output reloads on a jump instruction, but we
6776132718Skan	    can't subtract into that.  Fortunately a mov from lo to hi
6777132718Skan	    does not clobber the condition codes.  */
6778132718Skan	 output_asm_insn (\"sub\\t%1, %2, %3\", operands);
6779132718Skan	 output_asm_insn (\"mov\\t%0, %1\", operands);
6780132718Skan       }
6781132718Skan     else
6782132718Skan       {
6783132718Skan	 /* Similarly, but the target is memory.  */
6784132718Skan	 output_asm_insn (\"sub\\t%1, %2, %3\", operands);
6785132718Skan	 output_asm_insn (\"str\\t%1, %0\", operands);
6786132718Skan       }
6787132718Skan
6788132718Skan     switch (get_attr_length (insn) - ((which_alternative != 0) ? 2 : 0))
6789132718Skan       {
6790132718Skan	 case 4:
6791132718Skan	   return \"b%d4\\t%l5\";
6792132718Skan	 case 6:
6793132718Skan	   return \"b%D4\\t.LCB%=\;b\\t%l5\\t%@long jump\\n.LCB%=:\";
6794132718Skan	 default:
6795132718Skan	   return \"b%D4\\t.LCB%=\;bl\\t%l5\\t%@far jump\\n.LCB%=:\";
6796132718Skan       }
6797132718Skan   }
6798132718Skan  "
6799132718Skan  [(set (attr "far_jump")
6800132718Skan        (if_then_else
6801132718Skan	    (ior (and (eq (symbol_ref ("which_alternative"))
6802132718Skan	                  (const_int 0))
6803132718Skan		      (eq_attr "length" "8"))
6804132718Skan		 (eq_attr "length" "10"))
6805132718Skan	    (const_string "yes")
6806132718Skan            (const_string "no")))
6807132718Skan   (set (attr "length")
6808132718Skan     (if_then_else
6809132718Skan       (eq (symbol_ref ("which_alternative"))
6810132718Skan		       (const_int 0))
6811132718Skan       (if_then_else
6812132718Skan	 (and (ge (minus (match_dup 5) (pc)) (const_int -250))
6813132718Skan	      (le (minus (match_dup 5) (pc)) (const_int 256)))
6814132718Skan	 (const_int 4)
6815132718Skan	 (if_then_else
6816132718Skan	   (and (ge (minus (match_dup 5) (pc)) (const_int -2040))
6817132718Skan		(le (minus (match_dup 5) (pc)) (const_int 2048)))
6818132718Skan	   (const_int 6)
6819132718Skan	   (const_int 8)))
6820132718Skan       (if_then_else
6821132718Skan	 (and (ge (minus (match_dup 5) (pc)) (const_int -248))
6822132718Skan	      (le (minus (match_dup 5) (pc)) (const_int 256)))
6823132718Skan	 (const_int 6)
6824132718Skan	 (if_then_else
6825132718Skan	   (and (ge (minus (match_dup 5) (pc)) (const_int -2038))
6826132718Skan		(le (minus (match_dup 5) (pc)) (const_int 2048)))
6827132718Skan	   (const_int 8)
6828132718Skan	   (const_int 10)))))]
6829132718Skan)
6830132718Skan
6831132718Skan(define_insn "*subsi3_cbranch_scratch"
6832132718Skan  [(set (pc)
6833132718Skan	(if_then_else
6834132718Skan	 (match_operator 0 "arm_comparison_operator"
6835132718Skan	  [(minus:SI (match_operand:SI 1 "register_operand" "l")
6836132718Skan		     (match_operand:SI 2 "nonmemory_operand" "l"))
6837132718Skan	   (const_int 0)])
6838132718Skan	 (label_ref (match_operand 3 "" ""))
6839132718Skan	 (pc)))]
6840132718Skan  "TARGET_THUMB
6841132718Skan   && (GET_CODE (operands[0]) == EQ
6842132718Skan       || GET_CODE (operands[0]) == NE
6843132718Skan       || GET_CODE (operands[0]) == GE
6844132718Skan       || GET_CODE (operands[0]) == LT)"
6845132718Skan  "*
6846132718Skan  output_asm_insn (\"cmp\\t%1, %2\", operands);
6847132718Skan  switch (get_attr_length (insn))
6848132718Skan    {
6849132718Skan    case 4:  return \"b%d0\\t%l3\";
6850132718Skan    case 6:  return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
6851132718Skan    default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
6852132718Skan    }
6853132718Skan  "
6854132718Skan  [(set (attr "far_jump")
6855132718Skan        (if_then_else
6856132718Skan	    (eq_attr "length" "8")
6857132718Skan	    (const_string "yes")
6858132718Skan            (const_string "no")))
6859132718Skan   (set (attr "length") 
6860132718Skan        (if_then_else
6861132718Skan	    (and (ge (minus (match_dup 3) (pc)) (const_int -250))
6862132718Skan	         (le (minus (match_dup 3) (pc)) (const_int 256)))
6863132718Skan	    (const_int 4)
6864132718Skan	    (if_then_else
6865132718Skan	        (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
6866132718Skan		     (le (minus (match_dup 3) (pc)) (const_int 2048)))
6867132718Skan		(const_int 6)
6868132718Skan		(const_int 8))))]
6869132718Skan)
6870132718Skan
687190075Sobrien;; Comparison and test insns
687290075Sobrien
687390075Sobrien(define_expand "cmpsi"
687490075Sobrien  [(match_operand:SI 0 "s_register_operand" "")
687590075Sobrien   (match_operand:SI 1 "arm_add_operand" "")]
687690075Sobrien  "TARGET_ARM"
687790075Sobrien  "{
687890075Sobrien    arm_compare_op0 = operands[0];
687990075Sobrien    arm_compare_op1 = operands[1];
688090075Sobrien    DONE;
688190075Sobrien  }"
688290075Sobrien)
688390075Sobrien
688490075Sobrien(define_expand "cmpsf"
688590075Sobrien  [(match_operand:SF 0 "s_register_operand" "")
6886169689Skan   (match_operand:SF 1 "arm_float_compare_operand" "")]
6887169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT"
688890075Sobrien  "
688990075Sobrien  arm_compare_op0 = operands[0];
689090075Sobrien  arm_compare_op1 = operands[1];
689190075Sobrien  DONE;
689290075Sobrien  "
689390075Sobrien)
689490075Sobrien
689590075Sobrien(define_expand "cmpdf"
689690075Sobrien  [(match_operand:DF 0 "s_register_operand" "")
6897169689Skan   (match_operand:DF 1 "arm_float_compare_operand" "")]
6898169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT"
689990075Sobrien  "
690090075Sobrien  arm_compare_op0 = operands[0];
690190075Sobrien  arm_compare_op1 = operands[1];
690290075Sobrien  DONE;
690390075Sobrien  "
690490075Sobrien)
690590075Sobrien
690690075Sobrien(define_insn "*arm_cmpsi_insn"
690790075Sobrien  [(set (reg:CC CC_REGNUM)
690890075Sobrien	(compare:CC (match_operand:SI 0 "s_register_operand" "r,r")
690990075Sobrien		    (match_operand:SI 1 "arm_add_operand"    "rI,L")))]
691090075Sobrien  "TARGET_ARM"
691190075Sobrien  "@
691290075Sobrien   cmp%?\\t%0, %1
691390075Sobrien   cmn%?\\t%0, #%n1"
691490075Sobrien  [(set_attr "conds" "set")]
691590075Sobrien)
691690075Sobrien
691790075Sobrien(define_insn "*cmpsi_shiftsi"
691890075Sobrien  [(set (reg:CC CC_REGNUM)
691990075Sobrien	(compare:CC (match_operand:SI   0 "s_register_operand" "r")
692090075Sobrien		    (match_operator:SI  3 "shift_operator"
692190075Sobrien		     [(match_operand:SI 1 "s_register_operand" "r")
692290075Sobrien		      (match_operand:SI 2 "arm_rhs_operand"    "rM")])))]
692390075Sobrien  "TARGET_ARM"
692490075Sobrien  "cmp%?\\t%0, %1%S3"
692590075Sobrien  [(set_attr "conds" "set")
692690075Sobrien   (set_attr "shift" "1")
6927169689Skan   (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
6928169689Skan		      (const_string "alu_shift")
6929169689Skan		      (const_string "alu_shift_reg")))]
693090075Sobrien)
693190075Sobrien
693290075Sobrien(define_insn "*cmpsi_shiftsi_swp"
693390075Sobrien  [(set (reg:CC_SWP CC_REGNUM)
693490075Sobrien	(compare:CC_SWP (match_operator:SI 3 "shift_operator"
693590075Sobrien			 [(match_operand:SI 1 "s_register_operand" "r")
693690075Sobrien			  (match_operand:SI 2 "reg_or_int_operand" "rM")])
693790075Sobrien			(match_operand:SI 0 "s_register_operand" "r")))]
693890075Sobrien  "TARGET_ARM"
693990075Sobrien  "cmp%?\\t%0, %1%S3"
694090075Sobrien  [(set_attr "conds" "set")
694190075Sobrien   (set_attr "shift" "1")
6942169689Skan   (set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
6943169689Skan		      (const_string "alu_shift")
6944169689Skan		      (const_string "alu_shift_reg")))]
694590075Sobrien)
694690075Sobrien
6947169689Skan(define_insn "*cmpsi_negshiftsi_si"
6948169689Skan  [(set (reg:CC_Z CC_REGNUM)
6949169689Skan	(compare:CC_Z
6950169689Skan	 (neg:SI (match_operator:SI 1 "shift_operator"
6951169689Skan		    [(match_operand:SI 2 "s_register_operand" "r")
6952169689Skan		     (match_operand:SI 3 "reg_or_int_operand" "rM")]))
6953169689Skan	 (match_operand:SI 0 "s_register_operand" "r")))]
695490075Sobrien  "TARGET_ARM"
6955169689Skan  "cmn%?\\t%0, %2%S1"
695690075Sobrien  [(set_attr "conds" "set")
6957169689Skan   (set (attr "type") (if_then_else (match_operand 3 "const_int_operand" "")
6958169689Skan				    (const_string "alu_shift")
6959169689Skan				    (const_string "alu_shift_reg")))]
696090075Sobrien)
696190075Sobrien
6962132718Skan;; Cirrus SF compare instruction
6963132718Skan(define_insn "*cirrus_cmpsf"
696490075Sobrien  [(set (reg:CCFP CC_REGNUM)
6965132718Skan	(compare:CCFP (match_operand:SF 0 "cirrus_fp_register" "v")
6966132718Skan		      (match_operand:SF 1 "cirrus_fp_register" "v")))]
6967169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
6968132718Skan  "cfcmps%?\\tr15, %V0, %V1"
6969132718Skan  [(set_attr "type"   "mav_farith")
6970132718Skan   (set_attr "cirrus" "compare")]
697190075Sobrien)
697290075Sobrien
6973132718Skan;; Cirrus DF compare instruction
6974132718Skan(define_insn "*cirrus_cmpdf"
697590075Sobrien  [(set (reg:CCFP CC_REGNUM)
6976132718Skan	(compare:CCFP (match_operand:DF 0 "cirrus_fp_register" "v")
6977132718Skan		      (match_operand:DF 1 "cirrus_fp_register" "v")))]
6978169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
6979132718Skan  "cfcmpd%?\\tr15, %V0, %V1"
6980132718Skan  [(set_attr "type"   "mav_farith")
6981132718Skan   (set_attr "cirrus" "compare")]
698290075Sobrien)
698390075Sobrien
6984132718Skan;; Cirrus DI compare instruction
6985132718Skan(define_expand "cmpdi"
6986132718Skan  [(match_operand:DI 0 "cirrus_fp_register" "")
6987132718Skan   (match_operand:DI 1 "cirrus_fp_register" "")]
6988169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
6989132718Skan  "{
6990132718Skan     arm_compare_op0 = operands[0];
6991132718Skan     arm_compare_op1 = operands[1];
6992132718Skan     DONE;
6993132718Skan   }")
699490075Sobrien
6995132718Skan(define_insn "*cirrus_cmpdi"
6996132718Skan  [(set (reg:CC CC_REGNUM)
6997132718Skan	(compare:CC (match_operand:DI 0 "cirrus_fp_register" "v")
6998132718Skan		    (match_operand:DI 1 "cirrus_fp_register" "v")))]
6999169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK"
7000132718Skan  "cfcmp64%?\\tr15, %V0, %V1"
7001132718Skan  [(set_attr "type"   "mav_farith")
7002132718Skan   (set_attr "cirrus" "compare")]
700390075Sobrien)
700490075Sobrien
700590075Sobrien; This insn allows redundant compares to be removed by cse, nothing should
700690075Sobrien; ever appear in the output file since (set (reg x) (reg x)) is a no-op that
700790075Sobrien; is deleted later on. The match_dup will match the mode here, so that
700890075Sobrien; mode changes of the condition codes aren't lost by this even though we don't
700990075Sobrien; specify what they are.
701090075Sobrien
701190075Sobrien(define_insn "*deleted_compare"
701290075Sobrien  [(set (match_operand 0 "cc_register" "") (match_dup 0))]
701390075Sobrien  "TARGET_ARM"
701490075Sobrien  "\\t%@ deleted compare"
701590075Sobrien  [(set_attr "conds" "set")
701690075Sobrien   (set_attr "length" "0")]
701790075Sobrien)
701890075Sobrien
701990075Sobrien
702090075Sobrien;; Conditional branch insns
702190075Sobrien
702290075Sobrien(define_expand "beq"
702390075Sobrien  [(set (pc)
702490075Sobrien	(if_then_else (eq (match_dup 1) (const_int 0))
702590075Sobrien		      (label_ref (match_operand 0 "" ""))
702690075Sobrien		      (pc)))]
702790075Sobrien  "TARGET_ARM"
702890075Sobrien  "operands[1] = arm_gen_compare_reg (EQ, arm_compare_op0, arm_compare_op1);"
702990075Sobrien)
703090075Sobrien
703190075Sobrien(define_expand "bne"
703290075Sobrien  [(set (pc)
703390075Sobrien	(if_then_else (ne (match_dup 1) (const_int 0))
703490075Sobrien		      (label_ref (match_operand 0 "" ""))
703590075Sobrien		      (pc)))]
703690075Sobrien  "TARGET_ARM"
703790075Sobrien  "operands[1] = arm_gen_compare_reg (NE, arm_compare_op0, arm_compare_op1);"
703890075Sobrien)
703990075Sobrien
704090075Sobrien(define_expand "bgt"
704190075Sobrien  [(set (pc)
704290075Sobrien	(if_then_else (gt (match_dup 1) (const_int 0))
704390075Sobrien		      (label_ref (match_operand 0 "" ""))
704490075Sobrien		      (pc)))]
704590075Sobrien  "TARGET_ARM"
704690075Sobrien  "operands[1] = arm_gen_compare_reg (GT, arm_compare_op0, arm_compare_op1);"
704790075Sobrien)
704890075Sobrien
704990075Sobrien(define_expand "ble"
705090075Sobrien  [(set (pc)
705190075Sobrien	(if_then_else (le (match_dup 1) (const_int 0))
705290075Sobrien		      (label_ref (match_operand 0 "" ""))
705390075Sobrien		      (pc)))]
705490075Sobrien  "TARGET_ARM"
705590075Sobrien  "operands[1] = arm_gen_compare_reg (LE, arm_compare_op0, arm_compare_op1);"
705690075Sobrien)
705790075Sobrien
705890075Sobrien(define_expand "bge"
705990075Sobrien  [(set (pc)
706090075Sobrien	(if_then_else (ge (match_dup 1) (const_int 0))
706190075Sobrien		      (label_ref (match_operand 0 "" ""))
706290075Sobrien		      (pc)))]
706390075Sobrien  "TARGET_ARM"
706490075Sobrien  "operands[1] = arm_gen_compare_reg (GE, arm_compare_op0, arm_compare_op1);"
706590075Sobrien)
706690075Sobrien
706790075Sobrien(define_expand "blt"
706890075Sobrien  [(set (pc)
706990075Sobrien	(if_then_else (lt (match_dup 1) (const_int 0))
707090075Sobrien		      (label_ref (match_operand 0 "" ""))
707190075Sobrien		      (pc)))]
707290075Sobrien  "TARGET_ARM"
707390075Sobrien  "operands[1] = arm_gen_compare_reg (LT, arm_compare_op0, arm_compare_op1);"
707490075Sobrien)
707590075Sobrien
707690075Sobrien(define_expand "bgtu"
707790075Sobrien  [(set (pc)
707890075Sobrien	(if_then_else (gtu (match_dup 1) (const_int 0))
707990075Sobrien		      (label_ref (match_operand 0 "" ""))
708090075Sobrien		      (pc)))]
708190075Sobrien  "TARGET_ARM"
708290075Sobrien  "operands[1] = arm_gen_compare_reg (GTU, arm_compare_op0, arm_compare_op1);"
708390075Sobrien)
708490075Sobrien
708590075Sobrien(define_expand "bleu"
708690075Sobrien  [(set (pc)
708790075Sobrien	(if_then_else (leu (match_dup 1) (const_int 0))
708890075Sobrien		      (label_ref (match_operand 0 "" ""))
708990075Sobrien		      (pc)))]
709090075Sobrien  "TARGET_ARM"
709190075Sobrien  "operands[1] = arm_gen_compare_reg (LEU, arm_compare_op0, arm_compare_op1);"
709290075Sobrien)
709390075Sobrien
709490075Sobrien(define_expand "bgeu"
709590075Sobrien  [(set (pc)
709690075Sobrien	(if_then_else (geu (match_dup 1) (const_int 0))
709790075Sobrien		      (label_ref (match_operand 0 "" ""))
709890075Sobrien		      (pc)))]
709990075Sobrien  "TARGET_ARM"
710090075Sobrien  "operands[1] = arm_gen_compare_reg (GEU, arm_compare_op0, arm_compare_op1);"
710190075Sobrien)
710290075Sobrien
710390075Sobrien(define_expand "bltu"
710490075Sobrien  [(set (pc)
710590075Sobrien	(if_then_else (ltu (match_dup 1) (const_int 0))
710690075Sobrien		      (label_ref (match_operand 0 "" ""))
710790075Sobrien		      (pc)))]
710890075Sobrien  "TARGET_ARM"
710990075Sobrien  "operands[1] = arm_gen_compare_reg (LTU, arm_compare_op0, arm_compare_op1);"
711090075Sobrien)
711190075Sobrien
711290075Sobrien(define_expand "bunordered"
711390075Sobrien  [(set (pc)
711490075Sobrien	(if_then_else (unordered (match_dup 1) (const_int 0))
711590075Sobrien		      (label_ref (match_operand 0 "" ""))
711690075Sobrien		      (pc)))]
7117169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
711890075Sobrien  "operands[1] = arm_gen_compare_reg (UNORDERED, arm_compare_op0,
711990075Sobrien				      arm_compare_op1);"
712090075Sobrien)
712190075Sobrien
712290075Sobrien(define_expand "bordered"
712390075Sobrien  [(set (pc)
712490075Sobrien	(if_then_else (ordered (match_dup 1) (const_int 0))
712590075Sobrien		      (label_ref (match_operand 0 "" ""))
712690075Sobrien		      (pc)))]
7127169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
712890075Sobrien  "operands[1] = arm_gen_compare_reg (ORDERED, arm_compare_op0,
712990075Sobrien				      arm_compare_op1);"
713090075Sobrien)
713190075Sobrien
713290075Sobrien(define_expand "bungt"
713390075Sobrien  [(set (pc)
713490075Sobrien	(if_then_else (ungt (match_dup 1) (const_int 0))
713590075Sobrien		      (label_ref (match_operand 0 "" ""))
713690075Sobrien		      (pc)))]
7137169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
713890075Sobrien  "operands[1] = arm_gen_compare_reg (UNGT, arm_compare_op0, arm_compare_op1);"
713990075Sobrien)
714090075Sobrien
714190075Sobrien(define_expand "bunlt"
714290075Sobrien  [(set (pc)
714390075Sobrien	(if_then_else (unlt (match_dup 1) (const_int 0))
714490075Sobrien		      (label_ref (match_operand 0 "" ""))
714590075Sobrien		      (pc)))]
7146169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
714790075Sobrien  "operands[1] = arm_gen_compare_reg (UNLT, arm_compare_op0, arm_compare_op1);"
714890075Sobrien)
714990075Sobrien
715090075Sobrien(define_expand "bunge"
715190075Sobrien  [(set (pc)
715290075Sobrien	(if_then_else (unge (match_dup 1) (const_int 0))
715390075Sobrien		      (label_ref (match_operand 0 "" ""))
715490075Sobrien		      (pc)))]
7155169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
715690075Sobrien  "operands[1] = arm_gen_compare_reg (UNGE, arm_compare_op0, arm_compare_op1);"
715790075Sobrien)
715890075Sobrien
715990075Sobrien(define_expand "bunle"
716090075Sobrien  [(set (pc)
716190075Sobrien	(if_then_else (unle (match_dup 1) (const_int 0))
716290075Sobrien		      (label_ref (match_operand 0 "" ""))
716390075Sobrien		      (pc)))]
7164169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
716590075Sobrien  "operands[1] = arm_gen_compare_reg (UNLE, arm_compare_op0, arm_compare_op1);"
716690075Sobrien)
716790075Sobrien
716890075Sobrien;; The following two patterns need two branch instructions, since there is
716990075Sobrien;; no single instruction that will handle all cases.
717090075Sobrien(define_expand "buneq"
717190075Sobrien  [(set (pc)
717290075Sobrien	(if_then_else (uneq (match_dup 1) (const_int 0))
717390075Sobrien		      (label_ref (match_operand 0 "" ""))
717490075Sobrien		      (pc)))]
7175169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
717690075Sobrien  "operands[1] = arm_gen_compare_reg (UNEQ, arm_compare_op0, arm_compare_op1);"
717790075Sobrien)
717890075Sobrien
717990075Sobrien(define_expand "bltgt"
718090075Sobrien  [(set (pc)
718190075Sobrien	(if_then_else (ltgt (match_dup 1) (const_int 0))
718290075Sobrien		      (label_ref (match_operand 0 "" ""))
718390075Sobrien		      (pc)))]
7184169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
718590075Sobrien  "operands[1] = arm_gen_compare_reg (LTGT, arm_compare_op0, arm_compare_op1);"
718690075Sobrien)
718790075Sobrien
718890075Sobrien;;
718990075Sobrien;; Patterns to match conditional branch insns.
719090075Sobrien;;
719190075Sobrien
719290075Sobrien; Special pattern to match UNEQ.
719390075Sobrien(define_insn "*arm_buneq"
719490075Sobrien  [(set (pc)
719590075Sobrien	(if_then_else (uneq (match_operand 1 "cc_register" "") (const_int 0))
719690075Sobrien		      (label_ref (match_operand 0 "" ""))
719790075Sobrien		      (pc)))]
7198169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
719990075Sobrien  "*
7200169689Skan  gcc_assert (!arm_ccfsm_state);
720190075Sobrien
7202117395Skan  return \"bvs\\t%l0\;beq\\t%l0\";
720390075Sobrien  "
720490075Sobrien  [(set_attr "conds" "jump_clob")
720590075Sobrien   (set_attr "length" "8")]
720690075Sobrien)
720790075Sobrien
720890075Sobrien; Special pattern to match LTGT.
720990075Sobrien(define_insn "*arm_bltgt"
721090075Sobrien  [(set (pc)
721190075Sobrien	(if_then_else (ltgt (match_operand 1 "cc_register" "") (const_int 0))
721290075Sobrien		      (label_ref (match_operand 0 "" ""))
721390075Sobrien		      (pc)))]
7214169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
721590075Sobrien  "*
7216169689Skan  gcc_assert (!arm_ccfsm_state);
721790075Sobrien
7218117395Skan  return \"bmi\\t%l0\;bgt\\t%l0\";
721990075Sobrien  "
722090075Sobrien  [(set_attr "conds" "jump_clob")
722190075Sobrien   (set_attr "length" "8")]
722290075Sobrien)
722390075Sobrien
722490075Sobrien(define_insn "*arm_cond_branch"
722590075Sobrien  [(set (pc)
722690075Sobrien	(if_then_else (match_operator 1 "arm_comparison_operator"
722790075Sobrien		       [(match_operand 2 "cc_register" "") (const_int 0)])
722890075Sobrien		      (label_ref (match_operand 0 "" ""))
722990075Sobrien		      (pc)))]
723090075Sobrien  "TARGET_ARM"
723190075Sobrien  "*
723290075Sobrien  if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2)
723390075Sobrien    {
723490075Sobrien      arm_ccfsm_state += 2;
723590075Sobrien      return \"\";
723690075Sobrien    }
723790075Sobrien  return \"b%d1\\t%l0\";
723890075Sobrien  "
7239169689Skan  [(set_attr "conds" "use")
7240169689Skan   (set_attr "type" "branch")]
724190075Sobrien)
724290075Sobrien
724390075Sobrien; Special pattern to match reversed UNEQ.
724490075Sobrien(define_insn "*arm_buneq_reversed"
724590075Sobrien  [(set (pc)
724690075Sobrien	(if_then_else (uneq (match_operand 1 "cc_register" "") (const_int 0))
724790075Sobrien		      (pc)
724890075Sobrien		      (label_ref (match_operand 0 "" ""))))]
7249169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
725090075Sobrien  "*
7251169689Skan  gcc_assert (!arm_ccfsm_state);
725290075Sobrien
7253117395Skan  return \"bmi\\t%l0\;bgt\\t%l0\";
725490075Sobrien  "
725590075Sobrien  [(set_attr "conds" "jump_clob")
725690075Sobrien   (set_attr "length" "8")]
725790075Sobrien)
725890075Sobrien
725990075Sobrien; Special pattern to match reversed LTGT.
726090075Sobrien(define_insn "*arm_bltgt_reversed"
726190075Sobrien  [(set (pc)
726290075Sobrien	(if_then_else (ltgt (match_operand 1 "cc_register" "") (const_int 0))
726390075Sobrien		      (pc)
726490075Sobrien		      (label_ref (match_operand 0 "" ""))))]
7265169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
726690075Sobrien  "*
7267169689Skan  gcc_assert (!arm_ccfsm_state);
726890075Sobrien
7269117395Skan  return \"bvs\\t%l0\;beq\\t%l0\";
727090075Sobrien  "
727190075Sobrien  [(set_attr "conds" "jump_clob")
727290075Sobrien   (set_attr "length" "8")]
727390075Sobrien)
727490075Sobrien
727590075Sobrien(define_insn "*arm_cond_branch_reversed"
727690075Sobrien  [(set (pc)
727790075Sobrien	(if_then_else (match_operator 1 "arm_comparison_operator"
727890075Sobrien		       [(match_operand 2 "cc_register" "") (const_int 0)])
727990075Sobrien		      (pc)
728090075Sobrien		      (label_ref (match_operand 0 "" ""))))]
728190075Sobrien  "TARGET_ARM"
728290075Sobrien  "*
728390075Sobrien  if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2)
728490075Sobrien    {
728590075Sobrien      arm_ccfsm_state += 2;
728690075Sobrien      return \"\";
728790075Sobrien    }
728890075Sobrien  return \"b%D1\\t%l0\";
728990075Sobrien  "
7290169689Skan  [(set_attr "conds" "use")
7291169689Skan   (set_attr "type" "branch")]
729290075Sobrien)
729390075Sobrien
729490075Sobrien
729590075Sobrien
729690075Sobrien; scc insns
729790075Sobrien
729890075Sobrien(define_expand "seq"
7299132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
730090075Sobrien	(eq:SI (match_dup 1) (const_int 0)))]
730190075Sobrien  "TARGET_ARM"
730290075Sobrien  "operands[1] = arm_gen_compare_reg (EQ, arm_compare_op0, arm_compare_op1);"
730390075Sobrien)
730490075Sobrien
730590075Sobrien(define_expand "sne"
7306132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
730790075Sobrien	(ne:SI (match_dup 1) (const_int 0)))]
730890075Sobrien  "TARGET_ARM"
730990075Sobrien  "operands[1] = arm_gen_compare_reg (NE, arm_compare_op0, arm_compare_op1);"
731090075Sobrien)
731190075Sobrien
731290075Sobrien(define_expand "sgt"
7313132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
731490075Sobrien	(gt:SI (match_dup 1) (const_int 0)))]
731590075Sobrien  "TARGET_ARM"
731690075Sobrien  "operands[1] = arm_gen_compare_reg (GT, arm_compare_op0, arm_compare_op1);"
731790075Sobrien)
731890075Sobrien
731990075Sobrien(define_expand "sle"
7320132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
732190075Sobrien	(le:SI (match_dup 1) (const_int 0)))]
732290075Sobrien  "TARGET_ARM"
732390075Sobrien  "operands[1] = arm_gen_compare_reg (LE, arm_compare_op0, arm_compare_op1);"
732490075Sobrien)
732590075Sobrien
732690075Sobrien(define_expand "sge"
7327132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
732890075Sobrien	(ge:SI (match_dup 1) (const_int 0)))]
732990075Sobrien  "TARGET_ARM"
733090075Sobrien  "operands[1] = arm_gen_compare_reg (GE, arm_compare_op0, arm_compare_op1);"
733190075Sobrien)
733290075Sobrien
733390075Sobrien(define_expand "slt"
7334132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
733590075Sobrien	(lt:SI (match_dup 1) (const_int 0)))]
733690075Sobrien  "TARGET_ARM"
733790075Sobrien  "operands[1] = arm_gen_compare_reg (LT, arm_compare_op0, arm_compare_op1);"
733890075Sobrien)
733990075Sobrien
734090075Sobrien(define_expand "sgtu"
7341132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
734290075Sobrien	(gtu:SI (match_dup 1) (const_int 0)))]
734390075Sobrien  "TARGET_ARM"
734490075Sobrien  "operands[1] = arm_gen_compare_reg (GTU, arm_compare_op0, arm_compare_op1);"
734590075Sobrien)
734690075Sobrien
734790075Sobrien(define_expand "sleu"
7348132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
734990075Sobrien	(leu:SI (match_dup 1) (const_int 0)))]
735090075Sobrien  "TARGET_ARM"
735190075Sobrien  "operands[1] = arm_gen_compare_reg (LEU, arm_compare_op0, arm_compare_op1);"
735290075Sobrien)
735390075Sobrien
735490075Sobrien(define_expand "sgeu"
7355132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
735690075Sobrien	(geu:SI (match_dup 1) (const_int 0)))]
735790075Sobrien  "TARGET_ARM"
735890075Sobrien  "operands[1] = arm_gen_compare_reg (GEU, arm_compare_op0, arm_compare_op1);"
735990075Sobrien)
736090075Sobrien
736190075Sobrien(define_expand "sltu"
7362132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
736390075Sobrien	(ltu:SI (match_dup 1) (const_int 0)))]
736490075Sobrien  "TARGET_ARM"
736590075Sobrien  "operands[1] = arm_gen_compare_reg (LTU, arm_compare_op0, arm_compare_op1);"
736690075Sobrien)
736790075Sobrien
736890075Sobrien(define_expand "sunordered"
7369132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
737090075Sobrien	(unordered:SI (match_dup 1) (const_int 0)))]
7371169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
737290075Sobrien  "operands[1] = arm_gen_compare_reg (UNORDERED, arm_compare_op0,
737390075Sobrien				      arm_compare_op1);"
737490075Sobrien)
737590075Sobrien
737690075Sobrien(define_expand "sordered"
7377132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
737890075Sobrien	(ordered:SI (match_dup 1) (const_int 0)))]
7379169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
738090075Sobrien  "operands[1] = arm_gen_compare_reg (ORDERED, arm_compare_op0,
738190075Sobrien				      arm_compare_op1);"
738290075Sobrien)
738390075Sobrien
738490075Sobrien(define_expand "sungt"
7385132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
738690075Sobrien	(ungt:SI (match_dup 1) (const_int 0)))]
7387169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
738890075Sobrien  "operands[1] = arm_gen_compare_reg (UNGT, arm_compare_op0,
738990075Sobrien				      arm_compare_op1);"
739090075Sobrien)
739190075Sobrien
739290075Sobrien(define_expand "sunge"
7393132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
739490075Sobrien	(unge:SI (match_dup 1) (const_int 0)))]
7395169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
739690075Sobrien  "operands[1] = arm_gen_compare_reg (UNGE, arm_compare_op0,
739790075Sobrien				      arm_compare_op1);"
739890075Sobrien)
739990075Sobrien
740090075Sobrien(define_expand "sunlt"
7401132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
740290075Sobrien	(unlt:SI (match_dup 1) (const_int 0)))]
7403169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
740490075Sobrien  "operands[1] = arm_gen_compare_reg (UNLT, arm_compare_op0,
740590075Sobrien				      arm_compare_op1);"
740690075Sobrien)
740790075Sobrien
740890075Sobrien(define_expand "sunle"
7409132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
741090075Sobrien	(unle:SI (match_dup 1) (const_int 0)))]
7411169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
741290075Sobrien  "operands[1] = arm_gen_compare_reg (UNLE, arm_compare_op0,
741390075Sobrien				      arm_compare_op1);"
741490075Sobrien)
741590075Sobrien
741690075Sobrien;;; DO NOT add patterns for SUNEQ or SLTGT, these can't be represented with
741790075Sobrien;;; simple ARM instructions. 
741890075Sobrien;
741990075Sobrien; (define_expand "suneq"
7420132718Skan;   [(set (match_operand:SI 0 "s_register_operand" "")
742190075Sobrien; 	(uneq:SI (match_dup 1) (const_int 0)))]
7422169689Skan;   "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
7423169689Skan;   "gcc_unreachable ();"
742490075Sobrien; )
742590075Sobrien;
742690075Sobrien; (define_expand "sltgt"
7427132718Skan;   [(set (match_operand:SI 0 "s_register_operand" "")
742890075Sobrien; 	(ltgt:SI (match_dup 1) (const_int 0)))]
7429169689Skan;   "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
7430169689Skan;   "gcc_unreachable ();"
743190075Sobrien; )
743290075Sobrien
743390075Sobrien(define_insn "*mov_scc"
743490075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
743590075Sobrien	(match_operator:SI 1 "arm_comparison_operator"
743690075Sobrien	 [(match_operand 2 "cc_register" "") (const_int 0)]))]
743790075Sobrien  "TARGET_ARM"
743890075Sobrien  "mov%D1\\t%0, #0\;mov%d1\\t%0, #1"
743990075Sobrien  [(set_attr "conds" "use")
744090075Sobrien   (set_attr "length" "8")]
744190075Sobrien)
744290075Sobrien
744390075Sobrien(define_insn "*mov_negscc"
744490075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
744590075Sobrien	(neg:SI (match_operator:SI 1 "arm_comparison_operator"
744690075Sobrien		 [(match_operand 2 "cc_register" "") (const_int 0)])))]
744790075Sobrien  "TARGET_ARM"
744890075Sobrien  "mov%D1\\t%0, #0\;mvn%d1\\t%0, #0"
744990075Sobrien  [(set_attr "conds" "use")
745090075Sobrien   (set_attr "length" "8")]
745190075Sobrien)
745290075Sobrien
745390075Sobrien(define_insn "*mov_notscc"
745490075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
745590075Sobrien	(not:SI (match_operator:SI 1 "arm_comparison_operator"
745690075Sobrien		 [(match_operand 2 "cc_register" "") (const_int 0)])))]
745790075Sobrien  "TARGET_ARM"
745890075Sobrien  "mov%D1\\t%0, #0\;mvn%d1\\t%0, #1"
745990075Sobrien  [(set_attr "conds" "use")
746090075Sobrien   (set_attr "length" "8")]
746190075Sobrien)
746290075Sobrien
746390075Sobrien
746490075Sobrien;; Conditional move insns
746590075Sobrien
746690075Sobrien(define_expand "movsicc"
746790075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
746890075Sobrien	(if_then_else:SI (match_operand 1 "arm_comparison_operator" "")
746990075Sobrien			 (match_operand:SI 2 "arm_not_operand" "")
747090075Sobrien			 (match_operand:SI 3 "arm_not_operand" "")))]
747190075Sobrien  "TARGET_ARM"
747290075Sobrien  "
747390075Sobrien  {
747490075Sobrien    enum rtx_code code = GET_CODE (operands[1]);
7475117395Skan    rtx ccreg;
747690075Sobrien
7477117395Skan    if (code == UNEQ || code == LTGT)
7478117395Skan      FAIL;
7479117395Skan
7480117395Skan    ccreg = arm_gen_compare_reg (code, arm_compare_op0, arm_compare_op1);
7481169689Skan    operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx);
748290075Sobrien  }"
748390075Sobrien)
748490075Sobrien
748590075Sobrien(define_expand "movsfcc"
748690075Sobrien  [(set (match_operand:SF 0 "s_register_operand" "")
748790075Sobrien	(if_then_else:SF (match_operand 1 "arm_comparison_operator" "")
748890075Sobrien			 (match_operand:SF 2 "s_register_operand" "")
748990075Sobrien			 (match_operand:SF 3 "nonmemory_operand" "")))]
749090075Sobrien  "TARGET_ARM"
749190075Sobrien  "
749290075Sobrien  {
749390075Sobrien    enum rtx_code code = GET_CODE (operands[1]);
749490075Sobrien    rtx ccreg;
749590075Sobrien
7496117395Skan    if (code == UNEQ || code == LTGT)
7497117395Skan      FAIL;
7498117395Skan
749990075Sobrien    /* When compiling for SOFT_FLOAT, ensure both arms are in registers. 
7500169689Skan       Otherwise, ensure it is a valid FP add operand */
7501169689Skan    if ((!(TARGET_HARD_FLOAT && TARGET_FPA))
7502169689Skan        || (!arm_float_add_operand (operands[3], SFmode)))
750390075Sobrien      operands[3] = force_reg (SFmode, operands[3]);
750490075Sobrien
750590075Sobrien    ccreg = arm_gen_compare_reg (code, arm_compare_op0, arm_compare_op1);
7506169689Skan    operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx);
750790075Sobrien  }"
750890075Sobrien)
750990075Sobrien
751090075Sobrien(define_expand "movdfcc"
751190075Sobrien  [(set (match_operand:DF 0 "s_register_operand" "")
751290075Sobrien	(if_then_else:DF (match_operand 1 "arm_comparison_operator" "")
751390075Sobrien			 (match_operand:DF 2 "s_register_operand" "")
7514169689Skan			 (match_operand:DF 3 "arm_float_add_operand" "")))]
7515169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
751690075Sobrien  "
751790075Sobrien  {
751890075Sobrien    enum rtx_code code = GET_CODE (operands[1]);
7519117395Skan    rtx ccreg;
752090075Sobrien
7521117395Skan    if (code == UNEQ || code == LTGT)
7522117395Skan      FAIL;
7523117395Skan
7524117395Skan    ccreg = arm_gen_compare_reg (code, arm_compare_op0, arm_compare_op1);
7525169689Skan    operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx);
752690075Sobrien  }"
752790075Sobrien)
752890075Sobrien
752990075Sobrien(define_insn "*movsicc_insn"
753090075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r,r,r,r,r")
753190075Sobrien	(if_then_else:SI
753290075Sobrien	 (match_operator 3 "arm_comparison_operator"
753390075Sobrien	  [(match_operand 4 "cc_register" "") (const_int 0)])
753490075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,0,rI,K,rI,rI,K,K")
753590075Sobrien	 (match_operand:SI 2 "arm_not_operand" "rI,K,0,0,rI,K,rI,K")))]
753690075Sobrien  "TARGET_ARM"
753790075Sobrien  "@
753890075Sobrien   mov%D3\\t%0, %2
753990075Sobrien   mvn%D3\\t%0, #%B2
754090075Sobrien   mov%d3\\t%0, %1
754190075Sobrien   mvn%d3\\t%0, #%B1
754290075Sobrien   mov%d3\\t%0, %1\;mov%D3\\t%0, %2
754390075Sobrien   mov%d3\\t%0, %1\;mvn%D3\\t%0, #%B2
754490075Sobrien   mvn%d3\\t%0, #%B1\;mov%D3\\t%0, %2
754590075Sobrien   mvn%d3\\t%0, #%B1\;mvn%D3\\t%0, #%B2"
754690075Sobrien  [(set_attr "length" "4,4,4,4,8,8,8,8")
754790075Sobrien   (set_attr "conds" "use")]
754890075Sobrien)
754990075Sobrien
755090075Sobrien(define_insn "*movsfcc_soft_insn"
755190075Sobrien  [(set (match_operand:SF 0 "s_register_operand" "=r,r")
755290075Sobrien	(if_then_else:SF (match_operator 3 "arm_comparison_operator"
755390075Sobrien			  [(match_operand 4 "cc_register" "") (const_int 0)])
755490075Sobrien			 (match_operand:SF 1 "s_register_operand" "0,r")
755590075Sobrien			 (match_operand:SF 2 "s_register_operand" "r,0")))]
755690075Sobrien  "TARGET_ARM && TARGET_SOFT_FLOAT"
755790075Sobrien  "@
755890075Sobrien   mov%D3\\t%0, %2
755990075Sobrien   mov%d3\\t%0, %1"
756090075Sobrien  [(set_attr "conds" "use")]
756190075Sobrien)
756290075Sobrien
756390075Sobrien
756490075Sobrien;; Jump and linkage insns
756590075Sobrien
756690075Sobrien(define_expand "jump"
756790075Sobrien  [(set (pc)
756890075Sobrien	(label_ref (match_operand 0 "" "")))]
756990075Sobrien  "TARGET_EITHER"
757090075Sobrien  ""
757190075Sobrien)
757290075Sobrien
757390075Sobrien(define_insn "*arm_jump"
757490075Sobrien  [(set (pc)
757590075Sobrien	(label_ref (match_operand 0 "" "")))]
757690075Sobrien  "TARGET_ARM"
757790075Sobrien  "*
757890075Sobrien  {
757990075Sobrien    if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2)
758090075Sobrien      {
758190075Sobrien        arm_ccfsm_state += 2;
758290075Sobrien        return \"\";
758390075Sobrien      }
758490075Sobrien    return \"b%?\\t%l0\";
758590075Sobrien  }
758690075Sobrien  "
758790075Sobrien  [(set_attr "predicable" "yes")]
758890075Sobrien)
758990075Sobrien
759090075Sobrien(define_insn "*thumb_jump"
759190075Sobrien  [(set (pc)
759290075Sobrien	(label_ref (match_operand 0 "" "")))]
759390075Sobrien  "TARGET_THUMB"
759490075Sobrien  "*
759590075Sobrien  if (get_attr_length (insn) == 2)
759690075Sobrien    return \"b\\t%l0\";
759790075Sobrien  return \"bl\\t%l0\\t%@ far jump\";
759890075Sobrien  "
759990075Sobrien  [(set (attr "far_jump")
760090075Sobrien        (if_then_else
760190075Sobrien	    (eq_attr "length" "4")
760290075Sobrien	    (const_string "yes")
760390075Sobrien	    (const_string "no")))
760490075Sobrien   (set (attr "length") 
760590075Sobrien        (if_then_else
7606146895Skan	    (and (ge (minus (match_dup 0) (pc)) (const_int -2044))
7607146895Skan		 (le (minus (match_dup 0) (pc)) (const_int 2048)))
760890075Sobrien  	    (const_int 2)
760990075Sobrien	    (const_int 4)))]
761090075Sobrien)
761190075Sobrien
761290075Sobrien(define_expand "call"
761390075Sobrien  [(parallel [(call (match_operand 0 "memory_operand" "")
761490075Sobrien	            (match_operand 1 "general_operand" ""))
761590075Sobrien	      (use (match_operand 2 "" ""))
761690075Sobrien	      (clobber (reg:SI LR_REGNUM))])]
761790075Sobrien  "TARGET_EITHER"
761890075Sobrien  "
761990075Sobrien  {
762090075Sobrien    rtx callee;
762190075Sobrien    
762290075Sobrien    /* In an untyped call, we can get NULL for operand 2.  */
762390075Sobrien    if (operands[2] == NULL_RTX)
762490075Sobrien      operands[2] = const0_rtx;
762590075Sobrien      
762690075Sobrien    /* This is to decide if we should generate indirect calls by loading the
762790075Sobrien       32 bit address of the callee into a register before performing the
762890075Sobrien       branch and link.  operand[2] encodes the long_call/short_call
762990075Sobrien       attribute of the function being called.  This attribute is set whenever
763090075Sobrien       __attribute__((long_call/short_call)) or #pragma long_call/no_long_call
763190075Sobrien       is used, and the short_call attribute can also be set if function is
763290075Sobrien       declared as static or if it has already been defined in the current
763390075Sobrien       compilation unit.  See arm.c and arm.h for info about this.  The third
763490075Sobrien       parameter to arm_is_longcall_p is used to tell it which pattern
763590075Sobrien       invoked it.  */
763690075Sobrien    callee  = XEXP (operands[0], 0);
763790075Sobrien    
7638169689Skan    if ((GET_CODE (callee) == SYMBOL_REF
7639169689Skan	 && arm_is_longcall_p (operands[0], INTVAL (operands[2]), 0))
7640169689Skan	|| (GET_CODE (callee) != SYMBOL_REF
7641169689Skan	    && GET_CODE (callee) != REG))
764290075Sobrien      XEXP (operands[0], 0) = force_reg (Pmode, callee);
764390075Sobrien  }"
764490075Sobrien)
764590075Sobrien
7646169689Skan(define_insn "*call_reg_armv5"
764790075Sobrien  [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r"))
764890075Sobrien         (match_operand 1 "" ""))
764990075Sobrien   (use (match_operand 2 "" ""))
765090075Sobrien   (clobber (reg:SI LR_REGNUM))]
7651169689Skan  "TARGET_ARM && arm_arch5"
7652169689Skan  "blx%?\\t%0"
7653169689Skan  [(set_attr "type" "call")]
7654169689Skan)
7655169689Skan
7656169689Skan(define_insn "*call_reg_arm"
7657169689Skan  [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r"))
7658169689Skan         (match_operand 1 "" ""))
7659169689Skan   (use (match_operand 2 "" ""))
7660169689Skan   (clobber (reg:SI LR_REGNUM))]
7661169689Skan  "TARGET_ARM && !arm_arch5"
766290075Sobrien  "*
766390075Sobrien  return output_call (operands);
766490075Sobrien  "
766590075Sobrien  ;; length is worst case, normally it is only two
766690075Sobrien  [(set_attr "length" "12")
766790075Sobrien   (set_attr "type" "call")]
766890075Sobrien)
766990075Sobrien
767090075Sobrien(define_insn "*call_mem"
7671169689Skan  [(call (mem:SI (match_operand:SI 0 "call_memory_operand" "m"))
767290075Sobrien	 (match_operand 1 "" ""))
767390075Sobrien   (use (match_operand 2 "" ""))
767490075Sobrien   (clobber (reg:SI LR_REGNUM))]
767590075Sobrien  "TARGET_ARM"
767690075Sobrien  "*
767790075Sobrien  return output_call_mem (operands);
767890075Sobrien  "
767990075Sobrien  [(set_attr "length" "12")
768090075Sobrien   (set_attr "type" "call")]
768190075Sobrien)
768290075Sobrien
7683169689Skan(define_insn "*call_reg_thumb_v5"
768490075Sobrien  [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
768590075Sobrien	 (match_operand 1 "" ""))
768690075Sobrien   (use (match_operand 2 "" ""))
768790075Sobrien   (clobber (reg:SI LR_REGNUM))]
7688169689Skan  "TARGET_THUMB && arm_arch5"
7689169689Skan  "blx\\t%0"
7690169689Skan  [(set_attr "length" "2")
7691169689Skan   (set_attr "type" "call")]
769290075Sobrien)
769390075Sobrien
7694169689Skan(define_insn "*call_reg_thumb"
7695169689Skan  [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
7696169689Skan	 (match_operand 1 "" ""))
7697169689Skan   (use (match_operand 2 "" ""))
769890075Sobrien   (clobber (reg:SI LR_REGNUM))]
7699169689Skan  "TARGET_THUMB && !arm_arch5"
770090075Sobrien  "*
770190075Sobrien  {
7702169689Skan    if (!TARGET_CALLER_INTERWORKING)
7703169689Skan      return thumb_call_via_reg (operands[0]);
7704169689Skan    else if (operands[1] == const0_rtx)
7705169689Skan      return \"bl\\t%__interwork_call_via_%0\";
7706169689Skan    else if (frame_pointer_needed)
7707169689Skan      return \"bl\\t%__interwork_r7_call_via_%0\";
770890075Sobrien    else
7709169689Skan      return \"bl\\t%__interwork_r11_call_via_%0\";
771090075Sobrien  }"
771190075Sobrien  [(set_attr "type" "call")]
771290075Sobrien)
771390075Sobrien
771490075Sobrien(define_expand "call_value"
771590075Sobrien  [(parallel [(set (match_operand       0 "" "")
771690075Sobrien	           (call (match_operand 1 "memory_operand" "")
771790075Sobrien		         (match_operand 2 "general_operand" "")))
771890075Sobrien	      (use (match_operand 3 "" ""))
771990075Sobrien	      (clobber (reg:SI LR_REGNUM))])]
772090075Sobrien  "TARGET_EITHER"
772190075Sobrien  "
772290075Sobrien  {
772390075Sobrien    rtx callee = XEXP (operands[1], 0);
772490075Sobrien    
772590075Sobrien    /* In an untyped call, we can get NULL for operand 2.  */
772690075Sobrien    if (operands[3] == 0)
772790075Sobrien      operands[3] = const0_rtx;
772890075Sobrien      
772990075Sobrien    /* See the comment in define_expand \"call\".  */
7730169689Skan    if ((GET_CODE (callee) == SYMBOL_REF
7731169689Skan	 && arm_is_longcall_p (operands[1], INTVAL (operands[3]), 0))
7732169689Skan	|| (GET_CODE (callee) != SYMBOL_REF
7733169689Skan	    && GET_CODE (callee) != REG))
773490075Sobrien      XEXP (operands[1], 0) = force_reg (Pmode, callee);
773590075Sobrien  }"
773690075Sobrien)
773790075Sobrien
7738169689Skan(define_insn "*call_value_reg_armv5"
7739132718Skan  [(set (match_operand 0 "" "")
7740132718Skan        (call (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
774190075Sobrien	      (match_operand 2 "" "")))
774290075Sobrien   (use (match_operand 3 "" ""))
774390075Sobrien   (clobber (reg:SI LR_REGNUM))]
7744169689Skan  "TARGET_ARM && arm_arch5"
7745169689Skan  "blx%?\\t%1"
7746169689Skan  [(set_attr "type" "call")]
7747169689Skan)
7748169689Skan
7749169689Skan(define_insn "*call_value_reg_arm"
7750169689Skan  [(set (match_operand 0 "" "")
7751169689Skan        (call (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
7752169689Skan	      (match_operand 2 "" "")))
7753169689Skan   (use (match_operand 3 "" ""))
7754169689Skan   (clobber (reg:SI LR_REGNUM))]
7755169689Skan  "TARGET_ARM && !arm_arch5"
775690075Sobrien  "*
775790075Sobrien  return output_call (&operands[1]);
775890075Sobrien  "
775990075Sobrien  [(set_attr "length" "12")
776090075Sobrien   (set_attr "type" "call")]
776190075Sobrien)
776290075Sobrien
776390075Sobrien(define_insn "*call_value_mem"
7764132718Skan  [(set (match_operand 0 "" "")
7765169689Skan	(call (mem:SI (match_operand:SI 1 "call_memory_operand" "m"))
776690075Sobrien	      (match_operand 2 "" "")))
776790075Sobrien   (use (match_operand 3 "" ""))
776890075Sobrien   (clobber (reg:SI LR_REGNUM))]
776990075Sobrien  "TARGET_ARM && (!CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))"
777090075Sobrien  "*
777190075Sobrien  return output_call_mem (&operands[1]);
777290075Sobrien  "
777390075Sobrien  [(set_attr "length" "12")
777490075Sobrien   (set_attr "type" "call")]
777590075Sobrien)
777690075Sobrien
7777169689Skan(define_insn "*call_value_reg_thumb_v5"
7778169689Skan  [(set (match_operand 0 "" "")
7779169689Skan	(call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
7780169689Skan	      (match_operand 2 "" "")))
7781169689Skan   (use (match_operand 3 "" ""))
7782169689Skan   (clobber (reg:SI LR_REGNUM))]
7783169689Skan  "TARGET_THUMB && arm_arch5"
7784169689Skan  "blx\\t%1"
7785169689Skan  [(set_attr "length" "2")
7786169689Skan   (set_attr "type" "call")]
7787169689Skan)
7788169689Skan
7789169689Skan(define_insn "*call_value_reg_thumb"
7790169689Skan  [(set (match_operand 0 "" "")
7791169689Skan	(call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
7792169689Skan	      (match_operand 2 "" "")))
7793169689Skan   (use (match_operand 3 "" ""))
7794169689Skan   (clobber (reg:SI LR_REGNUM))]
7795169689Skan  "TARGET_THUMB && !arm_arch5"
7796169689Skan  "*
7797169689Skan  {
7798169689Skan    if (!TARGET_CALLER_INTERWORKING)
7799169689Skan      return thumb_call_via_reg (operands[1]);
7800169689Skan    else if (operands[2] == const0_rtx)
7801169689Skan      return \"bl\\t%__interwork_call_via_%1\";
7802169689Skan    else if (frame_pointer_needed)
7803169689Skan      return \"bl\\t%__interwork_r7_call_via_%1\";
7804169689Skan    else
7805169689Skan      return \"bl\\t%__interwork_r11_call_via_%1\";
7806169689Skan  }"
7807169689Skan  [(set_attr "type" "call")]
7808169689Skan)
7809169689Skan
781090075Sobrien;; Allow calls to SYMBOL_REFs specially as they are not valid general addresses
781190075Sobrien;; The 'a' causes the operand to be treated as an address, i.e. no '#' output.
781290075Sobrien
781390075Sobrien(define_insn "*call_symbol"
7814132718Skan  [(call (mem:SI (match_operand:SI 0 "" ""))
781590075Sobrien	 (match_operand 1 "" ""))
781690075Sobrien   (use (match_operand 2 "" ""))
781790075Sobrien   (clobber (reg:SI LR_REGNUM))]
781890075Sobrien  "TARGET_ARM
781990075Sobrien   && (GET_CODE (operands[0]) == SYMBOL_REF)
782090075Sobrien   && !arm_is_longcall_p (operands[0], INTVAL (operands[2]), 1)"
782190075Sobrien  "*
782290075Sobrien  {
782390075Sobrien    return NEED_PLT_RELOC ? \"bl%?\\t%a0(PLT)\" : \"bl%?\\t%a0\";
782490075Sobrien  }"
782590075Sobrien  [(set_attr "type" "call")]
782690075Sobrien)
782790075Sobrien
782890075Sobrien(define_insn "*call_value_symbol"
7829169689Skan  [(set (match_operand 0 "" "")
7830132718Skan	(call (mem:SI (match_operand:SI 1 "" ""))
783190075Sobrien	(match_operand:SI 2 "" "")))
783290075Sobrien   (use (match_operand 3 "" ""))
783390075Sobrien   (clobber (reg:SI LR_REGNUM))]
783490075Sobrien  "TARGET_ARM
783590075Sobrien   && (GET_CODE (operands[1]) == SYMBOL_REF)
783690075Sobrien   && !arm_is_longcall_p (operands[1], INTVAL (operands[3]), 1)"
783790075Sobrien  "*
783890075Sobrien  {
783990075Sobrien    return NEED_PLT_RELOC ? \"bl%?\\t%a1(PLT)\" : \"bl%?\\t%a1\";
784090075Sobrien  }"
784190075Sobrien  [(set_attr "type" "call")]
784290075Sobrien)
784390075Sobrien
784490075Sobrien(define_insn "*call_insn"
7845132718Skan  [(call (mem:SI (match_operand:SI 0 "" ""))
784690075Sobrien	 (match_operand:SI 1 "" ""))
784790075Sobrien   (use (match_operand 2 "" ""))
784890075Sobrien   (clobber (reg:SI LR_REGNUM))]
784990075Sobrien  "TARGET_THUMB
785096263Sobrien   && GET_CODE (operands[0]) == SYMBOL_REF
785196263Sobrien   && !arm_is_longcall_p (operands[0], INTVAL (operands[2]), 1)"
785290075Sobrien  "bl\\t%a0"
785390075Sobrien  [(set_attr "length" "4")
785490075Sobrien   (set_attr "type" "call")]
785590075Sobrien)
785690075Sobrien
785790075Sobrien(define_insn "*call_value_insn"
7858169689Skan  [(set (match_operand 0 "" "")
7859132718Skan	(call (mem:SI (match_operand 1 "" ""))
786090075Sobrien	      (match_operand 2 "" "")))
786190075Sobrien   (use (match_operand 3 "" ""))
786290075Sobrien   (clobber (reg:SI LR_REGNUM))]
786390075Sobrien  "TARGET_THUMB
786496263Sobrien   && GET_CODE (operands[1]) == SYMBOL_REF
786596263Sobrien   && !arm_is_longcall_p (operands[1], INTVAL (operands[3]), 1)"
786690075Sobrien  "bl\\t%a1"
786790075Sobrien  [(set_attr "length" "4")
786890075Sobrien   (set_attr "type" "call")]
786990075Sobrien)
787090075Sobrien
787190075Sobrien;; We may also be able to do sibcalls for Thumb, but it's much harder...
787290075Sobrien(define_expand "sibcall"
787390075Sobrien  [(parallel [(call (match_operand 0 "memory_operand" "")
787490075Sobrien		    (match_operand 1 "general_operand" ""))
7875117395Skan	      (return)
7876117395Skan	      (use (match_operand 2 "" ""))])]
787790075Sobrien  "TARGET_ARM"
787890075Sobrien  "
787990075Sobrien  {
788090075Sobrien    if (operands[2] == NULL_RTX)
788190075Sobrien      operands[2] = const0_rtx;
788290075Sobrien  }"
788390075Sobrien)
788490075Sobrien
788590075Sobrien(define_expand "sibcall_value"
7886169689Skan  [(parallel [(set (match_operand 0 "" "")
788790075Sobrien		   (call (match_operand 1 "memory_operand" "")
788890075Sobrien			 (match_operand 2 "general_operand" "")))
7889117395Skan	      (return)
7890117395Skan	      (use (match_operand 3 "" ""))])]
789190075Sobrien  "TARGET_ARM"
789290075Sobrien  "
789390075Sobrien  {
789490075Sobrien    if (operands[3] == NULL_RTX)
789590075Sobrien      operands[3] = const0_rtx;
789690075Sobrien  }"
789790075Sobrien)
789890075Sobrien
789990075Sobrien(define_insn "*sibcall_insn"
790090075Sobrien [(call (mem:SI (match_operand:SI 0 "" "X"))
790190075Sobrien	(match_operand 1 "" ""))
7902117395Skan  (return)
7903117395Skan  (use (match_operand 2 "" ""))]
790490075Sobrien  "TARGET_ARM && GET_CODE (operands[0]) == SYMBOL_REF"
790590075Sobrien  "*
790690075Sobrien  return NEED_PLT_RELOC ? \"b%?\\t%a0(PLT)\" : \"b%?\\t%a0\";
790790075Sobrien  "
790890075Sobrien  [(set_attr "type" "call")]
790990075Sobrien)
791090075Sobrien
791190075Sobrien(define_insn "*sibcall_value_insn"
7912169689Skan [(set (match_operand 0 "" "")
7913132718Skan       (call (mem:SI (match_operand:SI 1 "" "X"))
791490075Sobrien	     (match_operand 2 "" "")))
7915117395Skan  (return)
7916117395Skan  (use (match_operand 3 "" ""))]
791790075Sobrien  "TARGET_ARM && GET_CODE (operands[1]) == SYMBOL_REF"
791890075Sobrien  "*
791990075Sobrien  return NEED_PLT_RELOC ? \"b%?\\t%a1(PLT)\" : \"b%?\\t%a1\";
792090075Sobrien  "
792190075Sobrien  [(set_attr "type" "call")]
792290075Sobrien)
792390075Sobrien
792490075Sobrien;; Often the return insn will be the same as loading from memory, so set attr
792590075Sobrien(define_insn "return"
792690075Sobrien  [(return)]
792790075Sobrien  "TARGET_ARM && USE_RETURN_INSN (FALSE)"
792890075Sobrien  "*
792990075Sobrien  {
793090075Sobrien    if (arm_ccfsm_state == 2)
793190075Sobrien      {
793290075Sobrien        arm_ccfsm_state += 2;
793390075Sobrien        return \"\";
793490075Sobrien      }
7935117395Skan    return output_return_instruction (const_true_rtx, TRUE, FALSE);
793690075Sobrien  }"
7937169689Skan  [(set_attr "type" "load1")
7938132718Skan   (set_attr "length" "12")
793990075Sobrien   (set_attr "predicable" "yes")]
794090075Sobrien)
794190075Sobrien
794290075Sobrien(define_insn "*cond_return"
794390075Sobrien  [(set (pc)
794490075Sobrien        (if_then_else (match_operator 0 "arm_comparison_operator"
794590075Sobrien		       [(match_operand 1 "cc_register" "") (const_int 0)])
794690075Sobrien                      (return)
794790075Sobrien                      (pc)))]
794890075Sobrien  "TARGET_ARM && USE_RETURN_INSN (TRUE)"
794990075Sobrien  "*
795090075Sobrien  {
795190075Sobrien    if (arm_ccfsm_state == 2)
795290075Sobrien      {
795390075Sobrien        arm_ccfsm_state += 2;
795490075Sobrien        return \"\";
795590075Sobrien      }
795690075Sobrien    return output_return_instruction (operands[0], TRUE, FALSE);
795790075Sobrien  }"
795890075Sobrien  [(set_attr "conds" "use")
7959132718Skan   (set_attr "length" "12")
7960169689Skan   (set_attr "type" "load1")]
796190075Sobrien)
796290075Sobrien
796390075Sobrien(define_insn "*cond_return_inverted"
796490075Sobrien  [(set (pc)
796590075Sobrien        (if_then_else (match_operator 0 "arm_comparison_operator"
796690075Sobrien		       [(match_operand 1 "cc_register" "") (const_int 0)])
796790075Sobrien                      (pc)
796890075Sobrien		      (return)))]
796990075Sobrien  "TARGET_ARM && USE_RETURN_INSN (TRUE)"
797090075Sobrien  "*
797190075Sobrien  {
797290075Sobrien    if (arm_ccfsm_state == 2)
797390075Sobrien      {
797490075Sobrien        arm_ccfsm_state += 2;
797590075Sobrien        return \"\";
797690075Sobrien      }
797790075Sobrien    return output_return_instruction (operands[0], TRUE, TRUE);
797890075Sobrien  }"
797990075Sobrien  [(set_attr "conds" "use")
7980169689Skan   (set_attr "length" "12")
7981169689Skan   (set_attr "type" "load1")]
798290075Sobrien)
798390075Sobrien
7984117395Skan;; Generate a sequence of instructions to determine if the processor is
7985117395Skan;; in 26-bit or 32-bit mode, and return the appropriate return address
7986117395Skan;; mask.
7987117395Skan
7988117395Skan(define_expand "return_addr_mask"
7989117395Skan  [(set (match_dup 1)
7990117395Skan      (compare:CC_NOOV (unspec [(const_int 0)] UNSPEC_CHECK_ARCH)
7991117395Skan		       (const_int 0)))
7992117395Skan   (set (match_operand:SI 0 "s_register_operand" "")
7993117395Skan      (if_then_else:SI (eq (match_dup 1) (const_int 0))
7994117395Skan		       (const_int -1)
7995117395Skan		       (const_int 67108860)))] ; 0x03fffffc
7996117395Skan  "TARGET_ARM"
7997117395Skan  "
7998132718Skan  operands[1] = gen_rtx_REG (CC_NOOVmode, CC_REGNUM);
7999117395Skan  ")
8000117395Skan
8001117395Skan(define_insn "*check_arch2"
8002117395Skan  [(set (match_operand:CC_NOOV 0 "cc_register" "")
8003117395Skan      (compare:CC_NOOV (unspec [(const_int 0)] UNSPEC_CHECK_ARCH)
8004117395Skan		       (const_int 0)))]
8005117395Skan  "TARGET_ARM"
8006117395Skan  "teq\\t%|r0, %|r0\;teq\\t%|pc, %|pc"
8007117395Skan  [(set_attr "length" "8")
8008117395Skan   (set_attr "conds" "set")]
8009117395Skan)
8010117395Skan
801190075Sobrien;; Call subroutine returning any type.
801290075Sobrien
801390075Sobrien(define_expand "untyped_call"
801490075Sobrien  [(parallel [(call (match_operand 0 "" "")
801590075Sobrien		    (const_int 0))
801690075Sobrien	      (match_operand 1 "" "")
801790075Sobrien	      (match_operand 2 "" "")])]
8018169689Skan  "TARGET_EITHER"
801990075Sobrien  "
802090075Sobrien  {
802190075Sobrien    int i;
8022169689Skan    rtx par = gen_rtx_PARALLEL (VOIDmode,
8023169689Skan				rtvec_alloc (XVECLEN (operands[2], 0)));
8024169689Skan    rtx addr = gen_reg_rtx (Pmode);
8025169689Skan    rtx mem;
8026169689Skan    int size = 0;
802790075Sobrien
8028169689Skan    emit_move_insn (addr, XEXP (operands[1], 0));
8029169689Skan    mem = change_address (operands[1], BLKmode, addr);
803090075Sobrien
803190075Sobrien    for (i = 0; i < XVECLEN (operands[2], 0); i++)
803290075Sobrien      {
8033169689Skan	rtx src = SET_SRC (XVECEXP (operands[2], 0, i));
803490075Sobrien
8035169689Skan	/* Default code only uses r0 as a return value, but we could
8036169689Skan	   be using anything up to 4 registers.  */
8037169689Skan	if (REGNO (src) == R0_REGNUM)
8038169689Skan	  src = gen_rtx_REG (TImode, R0_REGNUM);
8039169689Skan
8040169689Skan        XVECEXP (par, 0, i) = gen_rtx_EXPR_LIST (VOIDmode, src,
8041169689Skan						 GEN_INT (size));
8042169689Skan        size += GET_MODE_SIZE (GET_MODE (src));
804390075Sobrien      }
804490075Sobrien
8045169689Skan    emit_call_insn (GEN_CALL_VALUE (par, operands[0], const0_rtx, NULL,
8046169689Skan				    const0_rtx));
8047169689Skan
8048169689Skan    size = 0;
8049169689Skan
8050169689Skan    for (i = 0; i < XVECLEN (par, 0); i++)
8051169689Skan      {
8052169689Skan	HOST_WIDE_INT offset = 0;
8053169689Skan	rtx reg = XEXP (XVECEXP (par, 0, i), 0);
8054169689Skan
8055169689Skan	if (size != 0)
8056169689Skan	  emit_move_insn (addr, plus_constant (addr, size));
8057169689Skan
8058169689Skan	mem = change_address (mem, GET_MODE (reg), NULL);
8059169689Skan	if (REGNO (reg) == R0_REGNUM)
8060169689Skan	  {
8061169689Skan	    /* On thumb we have to use a write-back instruction.  */
8062169689Skan	    emit_insn (arm_gen_store_multiple (R0_REGNUM, 4, addr, TRUE,
8063169689Skan			TARGET_THUMB ? TRUE : FALSE, mem, &offset));
8064169689Skan	    size = TARGET_ARM ? 16 : 0;
8065169689Skan	  }
8066169689Skan	else
8067169689Skan	  {
8068169689Skan	    emit_move_insn (mem, reg);
8069169689Skan	    size = GET_MODE_SIZE (GET_MODE (reg));
8070169689Skan	  }
8071169689Skan      }
8072169689Skan
807390075Sobrien    /* The optimizer does not know that the call sets the function value
807490075Sobrien       registers we stored in the result block.  We avoid problems by
807590075Sobrien       claiming that all hard registers are used and clobbered at this
807690075Sobrien       point.  */
807790075Sobrien    emit_insn (gen_blockage ());
807890075Sobrien
807990075Sobrien    DONE;
808090075Sobrien  }"
808190075Sobrien)
808290075Sobrien
8083169689Skan(define_expand "untyped_return"
8084169689Skan  [(match_operand:BLK 0 "memory_operand" "")
8085169689Skan   (match_operand 1 "" "")]
8086169689Skan  "TARGET_EITHER"
8087169689Skan  "
8088169689Skan  {
8089169689Skan    int i;
8090169689Skan    rtx addr = gen_reg_rtx (Pmode);
8091169689Skan    rtx mem;
8092169689Skan    int size = 0;
8093169689Skan
8094169689Skan    emit_move_insn (addr, XEXP (operands[0], 0));
8095169689Skan    mem = change_address (operands[0], BLKmode, addr);
8096169689Skan
8097169689Skan    for (i = 0; i < XVECLEN (operands[1], 0); i++)
8098169689Skan      {
8099169689Skan	HOST_WIDE_INT offset = 0;
8100169689Skan	rtx reg = SET_DEST (XVECEXP (operands[1], 0, i));
8101169689Skan
8102169689Skan	if (size != 0)
8103169689Skan	  emit_move_insn (addr, plus_constant (addr, size));
8104169689Skan
8105169689Skan	mem = change_address (mem, GET_MODE (reg), NULL);
8106169689Skan	if (REGNO (reg) == R0_REGNUM)
8107169689Skan	  {
8108169689Skan	    /* On thumb we have to use a write-back instruction.  */
8109169689Skan	    emit_insn (arm_gen_load_multiple (R0_REGNUM, 4, addr, TRUE,
8110169689Skan			TARGET_THUMB ? TRUE : FALSE, mem, &offset));
8111169689Skan	    size = TARGET_ARM ? 16 : 0;
8112169689Skan	  }
8113169689Skan	else
8114169689Skan	  {
8115169689Skan	    emit_move_insn (reg, mem);
8116169689Skan	    size = GET_MODE_SIZE (GET_MODE (reg));
8117169689Skan	  }
8118169689Skan      }
8119169689Skan
8120169689Skan    /* Emit USE insns before the return.  */
8121169689Skan    for (i = 0; i < XVECLEN (operands[1], 0); i++)
8122169689Skan      emit_insn (gen_rtx_USE (VOIDmode,
8123169689Skan			      SET_DEST (XVECEXP (operands[1], 0, i))));
8124169689Skan
8125169689Skan    /* Construct the return.  */
8126169689Skan    expand_naked_return ();
8127169689Skan
8128169689Skan    DONE;
8129169689Skan  }"
8130169689Skan)
8131169689Skan
813290075Sobrien;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
813390075Sobrien;; all of memory.  This blocks insns from being moved across this point.
813490075Sobrien
813590075Sobrien(define_insn "blockage"
813690075Sobrien  [(unspec_volatile [(const_int 0)] VUNSPEC_BLOCKAGE)]
813790075Sobrien  "TARGET_EITHER"
813890075Sobrien  ""
813990075Sobrien  [(set_attr "length" "0")
814090075Sobrien   (set_attr "type" "block")]
814190075Sobrien)
814290075Sobrien
814390075Sobrien(define_expand "casesi"
814490075Sobrien  [(match_operand:SI 0 "s_register_operand" "")	; index to jump on
814590075Sobrien   (match_operand:SI 1 "const_int_operand" "")	; lower bound
814690075Sobrien   (match_operand:SI 2 "const_int_operand" "")	; total range
814790075Sobrien   (match_operand:SI 3 "" "")			; table label
814890075Sobrien   (match_operand:SI 4 "" "")]			; Out of range label
814990075Sobrien  "TARGET_ARM"
815090075Sobrien  "
815190075Sobrien  {
815290075Sobrien    rtx reg;
815390075Sobrien    if (operands[1] != const0_rtx)
815490075Sobrien      {
815590075Sobrien	reg = gen_reg_rtx (SImode);
815690075Sobrien
815790075Sobrien	emit_insn (gen_addsi3 (reg, operands[0],
815890075Sobrien			       GEN_INT (-INTVAL (operands[1]))));
815990075Sobrien	operands[0] = reg;
816090075Sobrien      }
816190075Sobrien
816290075Sobrien    if (!const_ok_for_arm (INTVAL (operands[2])))
816390075Sobrien      operands[2] = force_reg (SImode, operands[2]);
816490075Sobrien
816590075Sobrien    emit_jump_insn (gen_casesi_internal (operands[0], operands[2], operands[3],
816690075Sobrien					 operands[4]));
816790075Sobrien    DONE;
816890075Sobrien  }"
816990075Sobrien)
817090075Sobrien
817190075Sobrien;; The USE in this pattern is needed to tell flow analysis that this is
817290075Sobrien;; a CASESI insn.  It has no other purpose.
817390075Sobrien(define_insn "casesi_internal"
817490075Sobrien  [(parallel [(set (pc)
817590075Sobrien	       (if_then_else
817690075Sobrien		(leu (match_operand:SI 0 "s_register_operand" "r")
817790075Sobrien		     (match_operand:SI 1 "arm_rhs_operand" "rI"))
817890075Sobrien		(mem:SI (plus:SI (mult:SI (match_dup 0) (const_int 4))
817990075Sobrien				 (label_ref (match_operand 2 "" ""))))
818090075Sobrien		(label_ref (match_operand 3 "" ""))))
818190075Sobrien	      (clobber (reg:CC CC_REGNUM))
818290075Sobrien	      (use (label_ref (match_dup 2)))])]
818390075Sobrien  "TARGET_ARM"
818490075Sobrien  "*
818590075Sobrien    if (flag_pic)
818690075Sobrien      return \"cmp\\t%0, %1\;addls\\t%|pc, %|pc, %0, asl #2\;b\\t%l3\";
818790075Sobrien    return   \"cmp\\t%0, %1\;ldrls\\t%|pc, [%|pc, %0, asl #2]\;b\\t%l3\";
818890075Sobrien  "
818990075Sobrien  [(set_attr "conds" "clob")
819090075Sobrien   (set_attr "length" "12")]
819190075Sobrien)
819290075Sobrien
819390075Sobrien(define_expand "indirect_jump"
819490075Sobrien  [(set (pc)
819590075Sobrien	(match_operand:SI 0 "s_register_operand" ""))]
819690075Sobrien  "TARGET_EITHER"
819790075Sobrien  ""
819890075Sobrien)
819990075Sobrien
8200169689Skan;; NB Never uses BX.
820190075Sobrien(define_insn "*arm_indirect_jump"
820290075Sobrien  [(set (pc)
820390075Sobrien	(match_operand:SI 0 "s_register_operand" "r"))]
820490075Sobrien  "TARGET_ARM"
820590075Sobrien  "mov%?\\t%|pc, %0\\t%@ indirect register jump"
820690075Sobrien  [(set_attr "predicable" "yes")]
820790075Sobrien)
820890075Sobrien
820990075Sobrien(define_insn "*load_indirect_jump"
821090075Sobrien  [(set (pc)
821190075Sobrien	(match_operand:SI 0 "memory_operand" "m"))]
821290075Sobrien  "TARGET_ARM"
821390075Sobrien  "ldr%?\\t%|pc, %0\\t%@ indirect memory jump"
8214169689Skan  [(set_attr "type" "load1")
821590075Sobrien   (set_attr "pool_range" "4096")
821690075Sobrien   (set_attr "neg_pool_range" "4084")
821790075Sobrien   (set_attr "predicable" "yes")]
821890075Sobrien)
821990075Sobrien
8220169689Skan;; NB Never uses BX.
822190075Sobrien(define_insn "*thumb_indirect_jump"
822290075Sobrien  [(set (pc)
822390075Sobrien	(match_operand:SI 0 "register_operand" "l*r"))]
822490075Sobrien  "TARGET_THUMB"
822590075Sobrien  "mov\\tpc, %0"
822690075Sobrien  [(set_attr "conds" "clob")
822790075Sobrien   (set_attr "length" "2")]
822890075Sobrien)
822990075Sobrien
823090075Sobrien
823190075Sobrien;; Misc insns
823290075Sobrien
823390075Sobrien(define_insn "nop"
823490075Sobrien  [(const_int 0)]
823590075Sobrien  "TARGET_EITHER"
823690075Sobrien  "*
823790075Sobrien  if (TARGET_ARM)
823890075Sobrien    return \"mov%?\\t%|r0, %|r0\\t%@ nop\";
823990075Sobrien  return  \"mov\\tr8, r8\";
824090075Sobrien  "
824190075Sobrien  [(set (attr "length")
824290075Sobrien	(if_then_else (eq_attr "is_thumb" "yes")
824390075Sobrien		      (const_int 2)
824490075Sobrien		      (const_int 4)))]
824590075Sobrien)
824690075Sobrien
824790075Sobrien
824890075Sobrien;; Patterns to allow combination of arithmetic, cond code and shifts
824990075Sobrien
825090075Sobrien(define_insn "*arith_shiftsi"
825190075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
825290075Sobrien        (match_operator:SI 1 "shiftable_operator"
825390075Sobrien          [(match_operator:SI 3 "shift_operator"
825490075Sobrien             [(match_operand:SI 4 "s_register_operand" "r")
825590075Sobrien              (match_operand:SI 5 "reg_or_int_operand" "rI")])
825690075Sobrien           (match_operand:SI 2 "s_register_operand" "r")]))]
825790075Sobrien  "TARGET_ARM"
825890075Sobrien  "%i1%?\\t%0, %2, %4%S3"
825990075Sobrien  [(set_attr "predicable" "yes")
826090075Sobrien   (set_attr "shift" "4")
8261169689Skan   (set (attr "type") (if_then_else (match_operand 5 "const_int_operand" "")
8262169689Skan		      (const_string "alu_shift")
8263169689Skan		      (const_string "alu_shift_reg")))]
826490075Sobrien)
826590075Sobrien
8266132718Skan(define_split
8267132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
8268132718Skan	(match_operator:SI 1 "shiftable_operator"
8269132718Skan	 [(match_operator:SI 2 "shiftable_operator"
8270132718Skan	   [(match_operator:SI 3 "shift_operator"
8271132718Skan	     [(match_operand:SI 4 "s_register_operand" "")
8272132718Skan	      (match_operand:SI 5 "reg_or_int_operand" "")])
8273132718Skan	    (match_operand:SI 6 "s_register_operand" "")])
8274132718Skan	  (match_operand:SI 7 "arm_rhs_operand" "")]))
8275132718Skan   (clobber (match_operand:SI 8 "s_register_operand" ""))]
8276132718Skan  "TARGET_ARM"
8277132718Skan  [(set (match_dup 8)
8278132718Skan	(match_op_dup 2 [(match_op_dup 3 [(match_dup 4) (match_dup 5)])
8279132718Skan			 (match_dup 6)]))
8280132718Skan   (set (match_dup 0)
8281132718Skan	(match_op_dup 1 [(match_dup 8) (match_dup 7)]))]
8282132718Skan  "")
8283132718Skan
828490075Sobrien(define_insn "*arith_shiftsi_compare0"
828590075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
828690075Sobrien        (compare:CC_NOOV (match_operator:SI 1 "shiftable_operator"
828790075Sobrien		          [(match_operator:SI 3 "shift_operator"
828890075Sobrien		            [(match_operand:SI 4 "s_register_operand" "r")
828990075Sobrien		             (match_operand:SI 5 "reg_or_int_operand" "rI")])
829090075Sobrien		           (match_operand:SI 2 "s_register_operand" "r")])
829190075Sobrien			 (const_int 0)))
829290075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
829390075Sobrien	(match_op_dup 1 [(match_op_dup 3 [(match_dup 4) (match_dup 5)])
829490075Sobrien			 (match_dup 2)]))]
829590075Sobrien  "TARGET_ARM"
829690075Sobrien  "%i1%?s\\t%0, %2, %4%S3"
829790075Sobrien  [(set_attr "conds" "set")
829890075Sobrien   (set_attr "shift" "4")
8299169689Skan   (set (attr "type") (if_then_else (match_operand 5 "const_int_operand" "")
8300169689Skan		      (const_string "alu_shift")
8301169689Skan		      (const_string "alu_shift_reg")))]
830290075Sobrien)
830390075Sobrien
830490075Sobrien(define_insn "*arith_shiftsi_compare0_scratch"
830590075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
830690075Sobrien        (compare:CC_NOOV (match_operator:SI 1 "shiftable_operator"
830790075Sobrien		          [(match_operator:SI 3 "shift_operator"
830890075Sobrien		            [(match_operand:SI 4 "s_register_operand" "r")
830990075Sobrien		             (match_operand:SI 5 "reg_or_int_operand" "rI")])
831090075Sobrien		           (match_operand:SI 2 "s_register_operand" "r")])
831190075Sobrien			 (const_int 0)))
831290075Sobrien   (clobber (match_scratch:SI 0 "=r"))]
831390075Sobrien  "TARGET_ARM"
831490075Sobrien  "%i1%?s\\t%0, %2, %4%S3"
831590075Sobrien  [(set_attr "conds" "set")
831690075Sobrien   (set_attr "shift" "4")
8317169689Skan   (set (attr "type") (if_then_else (match_operand 5 "const_int_operand" "")
8318169689Skan		      (const_string "alu_shift")
8319169689Skan		      (const_string "alu_shift_reg")))]
832090075Sobrien)
832190075Sobrien
832290075Sobrien(define_insn "*sub_shiftsi"
832390075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
832490075Sobrien	(minus:SI (match_operand:SI 1 "s_register_operand" "r")
832590075Sobrien		  (match_operator:SI 2 "shift_operator"
832690075Sobrien		   [(match_operand:SI 3 "s_register_operand" "r")
832790075Sobrien		    (match_operand:SI 4 "reg_or_int_operand" "rM")])))]
832890075Sobrien  "TARGET_ARM"
832990075Sobrien  "sub%?\\t%0, %1, %3%S2"
833090075Sobrien  [(set_attr "predicable" "yes")
833190075Sobrien   (set_attr "shift" "3")
8332169689Skan   (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "")
8333169689Skan		      (const_string "alu_shift")
8334169689Skan		      (const_string "alu_shift_reg")))]
833590075Sobrien)
833690075Sobrien
833790075Sobrien(define_insn "*sub_shiftsi_compare0"
833890075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
833990075Sobrien	(compare:CC_NOOV
834090075Sobrien	 (minus:SI (match_operand:SI 1 "s_register_operand" "r")
834190075Sobrien		   (match_operator:SI 2 "shift_operator"
834290075Sobrien		    [(match_operand:SI 3 "s_register_operand" "r")
834390075Sobrien		     (match_operand:SI 4 "reg_or_int_operand" "rM")]))
834490075Sobrien	 (const_int 0)))
834590075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
834690075Sobrien	(minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3)
834790075Sobrien						 (match_dup 4)])))]
834890075Sobrien  "TARGET_ARM"
834990075Sobrien  "sub%?s\\t%0, %1, %3%S2"
835090075Sobrien  [(set_attr "conds" "set")
8351169689Skan   (set_attr "shift" "3")
8352169689Skan   (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "")
8353169689Skan		      (const_string "alu_shift")
8354169689Skan		      (const_string "alu_shift_reg")))]
835590075Sobrien)
835690075Sobrien
835790075Sobrien(define_insn "*sub_shiftsi_compare0_scratch"
835890075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
835990075Sobrien	(compare:CC_NOOV
836090075Sobrien	 (minus:SI (match_operand:SI 1 "s_register_operand" "r")
836190075Sobrien		   (match_operator:SI 2 "shift_operator"
836290075Sobrien		    [(match_operand:SI 3 "s_register_operand" "r")
836390075Sobrien		     (match_operand:SI 4 "reg_or_int_operand" "rM")]))
836490075Sobrien	 (const_int 0)))
836590075Sobrien   (clobber (match_scratch:SI 0 "=r"))]
836690075Sobrien  "TARGET_ARM"
836790075Sobrien  "sub%?s\\t%0, %1, %3%S2"
836890075Sobrien  [(set_attr "conds" "set")
8369169689Skan   (set_attr "shift" "3")
8370169689Skan   (set (attr "type") (if_then_else (match_operand 4 "const_int_operand" "")
8371169689Skan		      (const_string "alu_shift")
8372169689Skan		      (const_string "alu_shift_reg")))]
837390075Sobrien)
837490075Sobrien
837590075Sobrien
837690075Sobrien
837790075Sobrien(define_insn "*and_scc"
837890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
837990075Sobrien	(and:SI (match_operator:SI 1 "arm_comparison_operator"
838090075Sobrien		 [(match_operand 3 "cc_register" "") (const_int 0)])
838190075Sobrien		(match_operand:SI 2 "s_register_operand" "r")))]
838290075Sobrien  "TARGET_ARM"
838390075Sobrien  "mov%D1\\t%0, #0\;and%d1\\t%0, %2, #1"
838490075Sobrien  [(set_attr "conds" "use")
838590075Sobrien   (set_attr "length" "8")]
838690075Sobrien)
838790075Sobrien
838890075Sobrien(define_insn "*ior_scc"
838990075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
839090075Sobrien	(ior:SI (match_operator:SI 2 "arm_comparison_operator"
839190075Sobrien		 [(match_operand 3 "cc_register" "") (const_int 0)])
839290075Sobrien		(match_operand:SI 1 "s_register_operand" "0,?r")))]
839390075Sobrien  "TARGET_ARM"
839490075Sobrien  "@
839590075Sobrien   orr%d2\\t%0, %1, #1
839690075Sobrien   mov%D2\\t%0, %1\;orr%d2\\t%0, %1, #1"
839790075Sobrien  [(set_attr "conds" "use")
839890075Sobrien   (set_attr "length" "4,8")]
839990075Sobrien)
840090075Sobrien
840190075Sobrien(define_insn "*compare_scc"
840290075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
840390075Sobrien	(match_operator:SI 1 "arm_comparison_operator"
840490075Sobrien	 [(match_operand:SI 2 "s_register_operand" "r,r")
840590075Sobrien	  (match_operand:SI 3 "arm_add_operand" "rI,L")]))
840690075Sobrien   (clobber (reg:CC CC_REGNUM))]
840790075Sobrien  "TARGET_ARM"
840890075Sobrien  "*
8409132718Skan    if (operands[3] == const0_rtx)
8410132718Skan      {
8411132718Skan	if (GET_CODE (operands[1]) == LT)
8412132718Skan	  return \"mov\\t%0, %2, lsr #31\";
841390075Sobrien
8414132718Skan	if (GET_CODE (operands[1]) == GE)
8415132718Skan	  return \"mvn\\t%0, %2\;mov\\t%0, %0, lsr #31\";
841690075Sobrien
8417132718Skan	if (GET_CODE (operands[1]) == EQ)
8418132718Skan	  return \"rsbs\\t%0, %2, #1\;movcc\\t%0, #0\";
8419132718Skan      }
8420132718Skan
842190075Sobrien    if (GET_CODE (operands[1]) == NE)
842290075Sobrien      {
842390075Sobrien        if (which_alternative == 1)
842490075Sobrien	  return \"adds\\t%0, %2, #%n3\;movne\\t%0, #1\";
842590075Sobrien        return \"subs\\t%0, %2, %3\;movne\\t%0, #1\";
842690075Sobrien      }
842790075Sobrien    if (which_alternative == 1)
842890075Sobrien      output_asm_insn (\"cmn\\t%2, #%n3\", operands);
842990075Sobrien    else
843090075Sobrien      output_asm_insn (\"cmp\\t%2, %3\", operands);
843190075Sobrien    return \"mov%D1\\t%0, #0\;mov%d1\\t%0, #1\";
843290075Sobrien  "
843390075Sobrien  [(set_attr "conds" "clob")
843490075Sobrien   (set_attr "length" "12")]
843590075Sobrien)
843690075Sobrien
843790075Sobrien(define_insn "*cond_move"
843890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
843990075Sobrien	(if_then_else:SI (match_operator 3 "equality_operator"
844090075Sobrien			  [(match_operator 4 "arm_comparison_operator"
844190075Sobrien			    [(match_operand 5 "cc_register" "") (const_int 0)])
844290075Sobrien			   (const_int 0)])
844390075Sobrien			 (match_operand:SI 1 "arm_rhs_operand" "0,rI,?rI")
844490075Sobrien			 (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")))]
844590075Sobrien  "TARGET_ARM"
844690075Sobrien  "*
844790075Sobrien    if (GET_CODE (operands[3]) == NE)
844890075Sobrien      {
844990075Sobrien        if (which_alternative != 1)
845090075Sobrien	  output_asm_insn (\"mov%D4\\t%0, %2\", operands);
845190075Sobrien        if (which_alternative != 0)
845290075Sobrien	  output_asm_insn (\"mov%d4\\t%0, %1\", operands);
845390075Sobrien        return \"\";
845490075Sobrien      }
845590075Sobrien    if (which_alternative != 0)
845690075Sobrien      output_asm_insn (\"mov%D4\\t%0, %1\", operands);
845790075Sobrien    if (which_alternative != 1)
845890075Sobrien      output_asm_insn (\"mov%d4\\t%0, %2\", operands);
845990075Sobrien    return \"\";
846090075Sobrien  "
846190075Sobrien  [(set_attr "conds" "use")
846290075Sobrien   (set_attr "length" "4,4,8")]
846390075Sobrien)
846490075Sobrien
846590075Sobrien(define_insn "*cond_arith"
846690075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
846790075Sobrien        (match_operator:SI 5 "shiftable_operator" 
846890075Sobrien	 [(match_operator:SI 4 "arm_comparison_operator"
846990075Sobrien           [(match_operand:SI 2 "s_register_operand" "r,r")
847090075Sobrien	    (match_operand:SI 3 "arm_rhs_operand" "rI,rI")])
847190075Sobrien          (match_operand:SI 1 "s_register_operand" "0,?r")]))
847290075Sobrien   (clobber (reg:CC CC_REGNUM))]
847390075Sobrien  "TARGET_ARM"
847490075Sobrien  "*
847590075Sobrien    if (GET_CODE (operands[4]) == LT && operands[3] == const0_rtx)
847690075Sobrien      return \"%i5\\t%0, %1, %2, lsr #31\";
847790075Sobrien
847890075Sobrien    output_asm_insn (\"cmp\\t%2, %3\", operands);
847990075Sobrien    if (GET_CODE (operands[5]) == AND)
848090075Sobrien      output_asm_insn (\"mov%D4\\t%0, #0\", operands);
848190075Sobrien    else if (GET_CODE (operands[5]) == MINUS)
848290075Sobrien      output_asm_insn (\"rsb%D4\\t%0, %1, #0\", operands);
848390075Sobrien    else if (which_alternative != 0)
848490075Sobrien      output_asm_insn (\"mov%D4\\t%0, %1\", operands);
848590075Sobrien    return \"%i5%d4\\t%0, %1, #1\";
848690075Sobrien  "
848790075Sobrien  [(set_attr "conds" "clob")
848890075Sobrien   (set_attr "length" "12")]
848990075Sobrien)
849090075Sobrien
849190075Sobrien(define_insn "*cond_sub"
849290075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
849390075Sobrien        (minus:SI (match_operand:SI 1 "s_register_operand" "0,?r")
849490075Sobrien		  (match_operator:SI 4 "arm_comparison_operator"
849590075Sobrien                   [(match_operand:SI 2 "s_register_operand" "r,r")
849690075Sobrien		    (match_operand:SI 3 "arm_rhs_operand" "rI,rI")])))
849790075Sobrien   (clobber (reg:CC CC_REGNUM))]
849890075Sobrien  "TARGET_ARM"
849990075Sobrien  "*
850090075Sobrien    output_asm_insn (\"cmp\\t%2, %3\", operands);
850190075Sobrien    if (which_alternative != 0)
850290075Sobrien      output_asm_insn (\"mov%D4\\t%0, %1\", operands);
850390075Sobrien    return \"sub%d4\\t%0, %1, #1\";
850490075Sobrien  "
850590075Sobrien  [(set_attr "conds" "clob")
850690075Sobrien   (set_attr "length" "8,12")]
850790075Sobrien)
850890075Sobrien
850990075Sobrien(define_insn "*cmp_ite0"
851090075Sobrien  [(set (match_operand 6 "dominant_cc_register" "")
851190075Sobrien	(compare
851290075Sobrien	 (if_then_else:SI
851390075Sobrien	  (match_operator 4 "arm_comparison_operator"
851490075Sobrien	   [(match_operand:SI 0 "s_register_operand" "r,r,r,r")
851590075Sobrien	    (match_operand:SI 1 "arm_add_operand" "rI,L,rI,L")])
851690075Sobrien	  (match_operator:SI 5 "arm_comparison_operator"
851790075Sobrien	   [(match_operand:SI 2 "s_register_operand" "r,r,r,r")
851890075Sobrien	    (match_operand:SI 3 "arm_add_operand" "rI,rI,L,L")])
851990075Sobrien	  (const_int 0))
852090075Sobrien	 (const_int 0)))]
852190075Sobrien  "TARGET_ARM"
852290075Sobrien  "*
852390075Sobrien  {
852490075Sobrien    static const char * const opcodes[4][2] =
852590075Sobrien    {
852690075Sobrien      {\"cmp\\t%2, %3\;cmp%d5\\t%0, %1\",
852790075Sobrien       \"cmp\\t%0, %1\;cmp%d4\\t%2, %3\"},
852890075Sobrien      {\"cmp\\t%2, %3\;cmn%d5\\t%0, #%n1\",
852990075Sobrien       \"cmn\\t%0, #%n1\;cmp%d4\\t%2, %3\"},
853090075Sobrien      {\"cmn\\t%2, #%n3\;cmp%d5\\t%0, %1\",
853190075Sobrien       \"cmp\\t%0, %1\;cmn%d4\\t%2, #%n3\"},
853290075Sobrien      {\"cmn\\t%2, #%n3\;cmn%d5\\t%0, #%n1\",
853390075Sobrien       \"cmn\\t%0, #%n1\;cmn%d4\\t%2, #%n3\"}
853490075Sobrien    };
853590075Sobrien    int swap =
853690075Sobrien      comparison_dominates_p (GET_CODE (operands[5]), GET_CODE (operands[4]));
853790075Sobrien
853890075Sobrien    return opcodes[which_alternative][swap];
853990075Sobrien  }"
854090075Sobrien  [(set_attr "conds" "set")
854190075Sobrien   (set_attr "length" "8")]
854290075Sobrien)
854390075Sobrien
854490075Sobrien(define_insn "*cmp_ite1"
854590075Sobrien  [(set (match_operand 6 "dominant_cc_register" "")
854690075Sobrien	(compare
854790075Sobrien	 (if_then_else:SI
854890075Sobrien	  (match_operator 4 "arm_comparison_operator"
854990075Sobrien	   [(match_operand:SI 0 "s_register_operand" "r,r,r,r")
855090075Sobrien	    (match_operand:SI 1 "arm_add_operand" "rI,L,rI,L")])
855190075Sobrien	  (match_operator:SI 5 "arm_comparison_operator"
855290075Sobrien	   [(match_operand:SI 2 "s_register_operand" "r,r,r,r")
855390075Sobrien	    (match_operand:SI 3 "arm_add_operand" "rI,rI,L,L")])
855490075Sobrien	  (const_int 1))
855590075Sobrien	 (const_int 0)))]
855690075Sobrien  "TARGET_ARM"
855790075Sobrien  "*
855890075Sobrien  {
855990075Sobrien    static const char * const opcodes[4][2] =
856090075Sobrien    {
856190075Sobrien      {\"cmp\\t%0, %1\;cmp%d4\\t%2, %3\",
856290075Sobrien       \"cmp\\t%2, %3\;cmp%D5\\t%0, %1\"},
856390075Sobrien      {\"cmn\\t%0, #%n1\;cmp%d4\\t%2, %3\",
856490075Sobrien       \"cmp\\t%2, %3\;cmn%D5\\t%0, #%n1\"},
856590075Sobrien      {\"cmp\\t%0, %1\;cmn%d4\\t%2, #%n3\",
856690075Sobrien       \"cmn\\t%2, #%n3\;cmp%D5\\t%0, %1\"},
856790075Sobrien      {\"cmn\\t%0, #%n1\;cmn%d4\\t%2, #%n3\",
856890075Sobrien       \"cmn\\t%2, #%n3\;cmn%D5\\t%0, #%n1\"}
856990075Sobrien    };
857090075Sobrien    int swap =
857190075Sobrien      comparison_dominates_p (GET_CODE (operands[5]),
857290075Sobrien			      reverse_condition (GET_CODE (operands[4])));
857390075Sobrien
857490075Sobrien    return opcodes[which_alternative][swap];
857590075Sobrien  }"
857690075Sobrien  [(set_attr "conds" "set")
857790075Sobrien   (set_attr "length" "8")]
857890075Sobrien)
857990075Sobrien
858090075Sobrien(define_insn "*cmp_and"
858190075Sobrien  [(set (match_operand 6 "dominant_cc_register" "")
858290075Sobrien	(compare
858390075Sobrien	 (and:SI
858490075Sobrien	  (match_operator 4 "arm_comparison_operator"
858590075Sobrien	   [(match_operand:SI 0 "s_register_operand" "r,r,r,r")
858690075Sobrien	    (match_operand:SI 1 "arm_add_operand" "rI,L,rI,L")])
858790075Sobrien	  (match_operator:SI 5 "arm_comparison_operator"
858890075Sobrien	   [(match_operand:SI 2 "s_register_operand" "r,r,r,r")
858990075Sobrien	    (match_operand:SI 3 "arm_add_operand" "rI,rI,L,L")]))
859090075Sobrien	 (const_int 0)))]
859190075Sobrien  "TARGET_ARM"
859290075Sobrien  "*
859390075Sobrien  {
859490075Sobrien    static const char *const opcodes[4][2] =
859590075Sobrien    {
859690075Sobrien      {\"cmp\\t%2, %3\;cmp%d5\\t%0, %1\",
859790075Sobrien       \"cmp\\t%0, %1\;cmp%d4\\t%2, %3\"},
859890075Sobrien      {\"cmp\\t%2, %3\;cmn%d5\\t%0, #%n1\",
859990075Sobrien       \"cmn\\t%0, #%n1\;cmp%d4\\t%2, %3\"},
860090075Sobrien      {\"cmn\\t%2, #%n3\;cmp%d5\\t%0, %1\",
860190075Sobrien       \"cmp\\t%0, %1\;cmn%d4\\t%2, #%n3\"},
860290075Sobrien      {\"cmn\\t%2, #%n3\;cmn%d5\\t%0, #%n1\",
860390075Sobrien       \"cmn\\t%0, #%n1\;cmn%d4\\t%2, #%n3\"}
860490075Sobrien    };
860590075Sobrien    int swap =
860690075Sobrien      comparison_dominates_p (GET_CODE (operands[5]), GET_CODE (operands[4]));
860790075Sobrien
860890075Sobrien    return opcodes[which_alternative][swap];
860990075Sobrien  }"
861090075Sobrien  [(set_attr "conds" "set")
861190075Sobrien   (set_attr "predicable" "no")
861290075Sobrien   (set_attr "length" "8")]
861390075Sobrien)
861490075Sobrien
861590075Sobrien(define_insn "*cmp_ior"
861690075Sobrien  [(set (match_operand 6 "dominant_cc_register" "")
861790075Sobrien	(compare
861890075Sobrien	 (ior:SI
861990075Sobrien	  (match_operator 4 "arm_comparison_operator"
862090075Sobrien	   [(match_operand:SI 0 "s_register_operand" "r,r,r,r")
862190075Sobrien	    (match_operand:SI 1 "arm_add_operand" "rI,L,rI,L")])
862290075Sobrien	  (match_operator:SI 5 "arm_comparison_operator"
862390075Sobrien	   [(match_operand:SI 2 "s_register_operand" "r,r,r,r")
862490075Sobrien	    (match_operand:SI 3 "arm_add_operand" "rI,rI,L,L")]))
862590075Sobrien	 (const_int 0)))]
862690075Sobrien  "TARGET_ARM"
862790075Sobrien  "*
862890075Sobrien{
862990075Sobrien  static const char *const opcodes[4][2] =
863090075Sobrien  {
863190075Sobrien    {\"cmp\\t%0, %1\;cmp%D4\\t%2, %3\",
863290075Sobrien     \"cmp\\t%2, %3\;cmp%D5\\t%0, %1\"},
863390075Sobrien    {\"cmn\\t%0, #%n1\;cmp%D4\\t%2, %3\",
863490075Sobrien     \"cmp\\t%2, %3\;cmn%D5\\t%0, #%n1\"},
863590075Sobrien    {\"cmp\\t%0, %1\;cmn%D4\\t%2, #%n3\",
863690075Sobrien     \"cmn\\t%2, #%n3\;cmp%D5\\t%0, %1\"},
863790075Sobrien    {\"cmn\\t%0, #%n1\;cmn%D4\\t%2, #%n3\",
863890075Sobrien     \"cmn\\t%2, #%n3\;cmn%D5\\t%0, #%n1\"}
863990075Sobrien  };
864090075Sobrien  int swap =
864190075Sobrien    comparison_dominates_p (GET_CODE (operands[5]), GET_CODE (operands[4]));
864290075Sobrien
864390075Sobrien  return opcodes[which_alternative][swap];
864490075Sobrien}
864590075Sobrien"
864690075Sobrien  [(set_attr "conds" "set")
864790075Sobrien   (set_attr "length" "8")]
864890075Sobrien)
864990075Sobrien
8650132718Skan(define_insn_and_split "*ior_scc_scc"
8651132718Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
8652132718Skan	(ior:SI (match_operator:SI 3 "arm_comparison_operator"
8653132718Skan		 [(match_operand:SI 1 "s_register_operand" "r")
8654132718Skan		  (match_operand:SI 2 "arm_add_operand" "rIL")])
8655132718Skan		(match_operator:SI 6 "arm_comparison_operator"
8656132718Skan		 [(match_operand:SI 4 "s_register_operand" "r")
8657132718Skan		  (match_operand:SI 5 "arm_add_operand" "rIL")])))
8658132718Skan   (clobber (reg:CC CC_REGNUM))]
8659132718Skan  "TARGET_ARM
8660132718Skan   && (arm_select_dominance_cc_mode (operands[3], operands[6], DOM_CC_X_OR_Y)
8661132718Skan       != CCmode)"
8662132718Skan  "#"
8663132718Skan  "TARGET_ARM && reload_completed"
8664132718Skan  [(set (match_dup 7)
8665132718Skan	(compare
8666132718Skan	 (ior:SI
8667132718Skan	  (match_op_dup 3 [(match_dup 1) (match_dup 2)])
8668132718Skan	  (match_op_dup 6 [(match_dup 4) (match_dup 5)]))
8669132718Skan	 (const_int 0)))
8670132718Skan   (set (match_dup 0) (ne:SI (match_dup 7) (const_int 0)))]
8671132718Skan  "operands[7]
8672132718Skan     = gen_rtx_REG (arm_select_dominance_cc_mode (operands[3], operands[6],
8673132718Skan						  DOM_CC_X_OR_Y),
8674132718Skan		    CC_REGNUM);"
8675132718Skan  [(set_attr "conds" "clob")
8676132718Skan   (set_attr "length" "16")])
8677132718Skan
8678132718Skan; If the above pattern is followed by a CMP insn, then the compare is 
8679132718Skan; redundant, since we can rework the conditional instruction that follows.
8680132718Skan(define_insn_and_split "*ior_scc_scc_cmp"
8681132718Skan  [(set (match_operand 0 "dominant_cc_register" "")
8682132718Skan	(compare (ior:SI (match_operator:SI 3 "arm_comparison_operator"
8683132718Skan			  [(match_operand:SI 1 "s_register_operand" "r")
8684132718Skan			   (match_operand:SI 2 "arm_add_operand" "rIL")])
8685132718Skan			 (match_operator:SI 6 "arm_comparison_operator"
8686132718Skan			  [(match_operand:SI 4 "s_register_operand" "r")
8687132718Skan			   (match_operand:SI 5 "arm_add_operand" "rIL")]))
8688132718Skan		 (const_int 0)))
8689132718Skan   (set (match_operand:SI 7 "s_register_operand" "=r")
8690132718Skan	(ior:SI (match_op_dup 3 [(match_dup 1) (match_dup 2)])
8691132718Skan		(match_op_dup 6 [(match_dup 4) (match_dup 5)])))]
8692132718Skan  "TARGET_ARM"
8693132718Skan  "#"
8694132718Skan  "TARGET_ARM && reload_completed"
8695132718Skan  [(set (match_dup 0)
8696132718Skan	(compare
8697132718Skan	 (ior:SI
8698132718Skan	  (match_op_dup 3 [(match_dup 1) (match_dup 2)])
8699132718Skan	  (match_op_dup 6 [(match_dup 4) (match_dup 5)]))
8700132718Skan	 (const_int 0)))
8701132718Skan   (set (match_dup 7) (ne:SI (match_dup 0) (const_int 0)))]
8702132718Skan  ""
8703132718Skan  [(set_attr "conds" "set")
8704132718Skan   (set_attr "length" "16")])
8705132718Skan
8706132718Skan(define_insn_and_split "*and_scc_scc"
8707132718Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
8708132718Skan	(and:SI (match_operator:SI 3 "arm_comparison_operator"
8709132718Skan		 [(match_operand:SI 1 "s_register_operand" "r")
8710132718Skan		  (match_operand:SI 2 "arm_add_operand" "rIL")])
8711132718Skan		(match_operator:SI 6 "arm_comparison_operator"
8712132718Skan		 [(match_operand:SI 4 "s_register_operand" "r")
8713132718Skan		  (match_operand:SI 5 "arm_add_operand" "rIL")])))
8714132718Skan   (clobber (reg:CC CC_REGNUM))]
8715132718Skan  "TARGET_ARM
8716132718Skan   && (arm_select_dominance_cc_mode (operands[3], operands[6], DOM_CC_X_AND_Y)
8717132718Skan       != CCmode)"
8718132718Skan  "#"
8719132718Skan  "TARGET_ARM && reload_completed
8720132718Skan   && (arm_select_dominance_cc_mode (operands[3], operands[6], DOM_CC_X_AND_Y)
8721132718Skan       != CCmode)"
8722132718Skan  [(set (match_dup 7)
8723132718Skan	(compare
8724132718Skan	 (and:SI
8725132718Skan	  (match_op_dup 3 [(match_dup 1) (match_dup 2)])
8726132718Skan	  (match_op_dup 6 [(match_dup 4) (match_dup 5)]))
8727132718Skan	 (const_int 0)))
8728132718Skan   (set (match_dup 0) (ne:SI (match_dup 7) (const_int 0)))]
8729132718Skan  "operands[7]
8730132718Skan     = gen_rtx_REG (arm_select_dominance_cc_mode (operands[3], operands[6],
8731132718Skan						  DOM_CC_X_AND_Y),
8732132718Skan		    CC_REGNUM);"
8733132718Skan  [(set_attr "conds" "clob")
8734132718Skan   (set_attr "length" "16")])
8735132718Skan
8736132718Skan; If the above pattern is followed by a CMP insn, then the compare is 
8737132718Skan; redundant, since we can rework the conditional instruction that follows.
8738132718Skan(define_insn_and_split "*and_scc_scc_cmp"
8739132718Skan  [(set (match_operand 0 "dominant_cc_register" "")
8740132718Skan	(compare (and:SI (match_operator:SI 3 "arm_comparison_operator"
8741132718Skan			  [(match_operand:SI 1 "s_register_operand" "r")
8742132718Skan			   (match_operand:SI 2 "arm_add_operand" "rIL")])
8743132718Skan			 (match_operator:SI 6 "arm_comparison_operator"
8744132718Skan			  [(match_operand:SI 4 "s_register_operand" "r")
8745132718Skan			   (match_operand:SI 5 "arm_add_operand" "rIL")]))
8746132718Skan		 (const_int 0)))
8747132718Skan   (set (match_operand:SI 7 "s_register_operand" "=r")
8748132718Skan	(and:SI (match_op_dup 3 [(match_dup 1) (match_dup 2)])
8749132718Skan		(match_op_dup 6 [(match_dup 4) (match_dup 5)])))]
8750132718Skan  "TARGET_ARM"
8751132718Skan  "#"
8752132718Skan  "TARGET_ARM && reload_completed"
8753132718Skan  [(set (match_dup 0)
8754132718Skan	(compare
8755132718Skan	 (and:SI
8756132718Skan	  (match_op_dup 3 [(match_dup 1) (match_dup 2)])
8757132718Skan	  (match_op_dup 6 [(match_dup 4) (match_dup 5)]))
8758132718Skan	 (const_int 0)))
8759132718Skan   (set (match_dup 7) (ne:SI (match_dup 0) (const_int 0)))]
8760132718Skan  ""
8761132718Skan  [(set_attr "conds" "set")
8762132718Skan   (set_attr "length" "16")])
8763132718Skan
8764132718Skan;; If there is no dominance in the comparison, then we can still save an
8765132718Skan;; instruction in the AND case, since we can know that the second compare
8766132718Skan;; need only zero the value if false (if true, then the value is already
8767132718Skan;; correct).
8768132718Skan(define_insn_and_split "*and_scc_scc_nodom"
8769132718Skan  [(set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r")
8770132718Skan	(and:SI (match_operator:SI 3 "arm_comparison_operator"
8771132718Skan		 [(match_operand:SI 1 "s_register_operand" "r,r,0")
8772132718Skan		  (match_operand:SI 2 "arm_add_operand" "rIL,0,rIL")])
8773132718Skan		(match_operator:SI 6 "arm_comparison_operator"
8774132718Skan		 [(match_operand:SI 4 "s_register_operand" "r,r,r")
8775132718Skan		  (match_operand:SI 5 "arm_add_operand" "rIL,rIL,rIL")])))
8776132718Skan   (clobber (reg:CC CC_REGNUM))]
8777132718Skan  "TARGET_ARM
8778132718Skan   && (arm_select_dominance_cc_mode (operands[3], operands[6], DOM_CC_X_AND_Y)
8779132718Skan       == CCmode)"
8780132718Skan  "#"
8781132718Skan  "TARGET_ARM && reload_completed"
8782132718Skan  [(parallel [(set (match_dup 0)
8783132718Skan		   (match_op_dup 3 [(match_dup 1) (match_dup 2)]))
8784132718Skan	      (clobber (reg:CC CC_REGNUM))])
8785132718Skan   (set (match_dup 7) (match_op_dup 8 [(match_dup 4) (match_dup 5)]))
8786132718Skan   (set (match_dup 0)
8787132718Skan	(if_then_else:SI (match_op_dup 6 [(match_dup 7) (const_int 0)])
8788132718Skan			 (match_dup 0)
8789132718Skan			 (const_int 0)))]
8790132718Skan  "operands[7] = gen_rtx_REG (SELECT_CC_MODE (GET_CODE (operands[6]),
8791132718Skan					      operands[4], operands[5]),
8792132718Skan			      CC_REGNUM);
8793132718Skan   operands[8] = gen_rtx_COMPARE (GET_MODE (operands[7]), operands[4],
8794132718Skan				  operands[5]);"
8795132718Skan  [(set_attr "conds" "clob")
8796132718Skan   (set_attr "length" "20")])
8797132718Skan
8798132718Skan(define_split
8799132718Skan  [(set (reg:CC_NOOV CC_REGNUM)
8800132718Skan	(compare:CC_NOOV (ior:SI
8801132718Skan			  (and:SI (match_operand:SI 0 "s_register_operand" "")
8802132718Skan				  (const_int 1))
8803132718Skan			  (match_operator:SI 1 "comparison_operator"
8804132718Skan			   [(match_operand:SI 2 "s_register_operand" "")
8805132718Skan			    (match_operand:SI 3 "arm_add_operand" "")]))
8806132718Skan			 (const_int 0)))
8807132718Skan   (clobber (match_operand:SI 4 "s_register_operand" ""))]
8808132718Skan  "TARGET_ARM"
8809132718Skan  [(set (match_dup 4)
8810132718Skan	(ior:SI (match_op_dup 1 [(match_dup 2) (match_dup 3)])
8811132718Skan		(match_dup 0)))
8812132718Skan   (set (reg:CC_NOOV CC_REGNUM)
8813132718Skan	(compare:CC_NOOV (and:SI (match_dup 4) (const_int 1))
8814132718Skan			 (const_int 0)))]
8815132718Skan  "")
8816132718Skan
8817132718Skan(define_split
8818132718Skan  [(set (reg:CC_NOOV CC_REGNUM)
8819132718Skan	(compare:CC_NOOV (ior:SI
8820132718Skan			  (match_operator:SI 1 "comparison_operator"
8821132718Skan			   [(match_operand:SI 2 "s_register_operand" "")
8822132718Skan			    (match_operand:SI 3 "arm_add_operand" "")])
8823132718Skan			  (and:SI (match_operand:SI 0 "s_register_operand" "")
8824132718Skan				  (const_int 1)))
8825132718Skan			 (const_int 0)))
8826132718Skan   (clobber (match_operand:SI 4 "s_register_operand" ""))]
8827132718Skan  "TARGET_ARM"
8828132718Skan  [(set (match_dup 4)
8829132718Skan	(ior:SI (match_op_dup 1 [(match_dup 2) (match_dup 3)])
8830132718Skan		(match_dup 0)))
8831132718Skan   (set (reg:CC_NOOV CC_REGNUM)
8832132718Skan	(compare:CC_NOOV (and:SI (match_dup 4) (const_int 1))
8833132718Skan			 (const_int 0)))]
8834132718Skan  "")
8835132718Skan
883690075Sobrien(define_insn "*negscc"
883790075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
883890075Sobrien	(neg:SI (match_operator 3 "arm_comparison_operator"
883990075Sobrien		 [(match_operand:SI 1 "s_register_operand" "r")
884090075Sobrien		  (match_operand:SI 2 "arm_rhs_operand" "rI")])))
884190075Sobrien   (clobber (reg:CC CC_REGNUM))]
884290075Sobrien  "TARGET_ARM"
884390075Sobrien  "*
8844260455Spfg  if (GET_CODE (operands[3]) == LT && operands[2] == const0_rtx)
884590075Sobrien    return \"mov\\t%0, %1, asr #31\";
884690075Sobrien
884790075Sobrien  if (GET_CODE (operands[3]) == NE)
884890075Sobrien    return \"subs\\t%0, %1, %2\;mvnne\\t%0, #0\";
884990075Sobrien
885090075Sobrien  output_asm_insn (\"cmp\\t%1, %2\", operands);
885190075Sobrien  output_asm_insn (\"mov%D3\\t%0, #0\", operands);
885290075Sobrien  return \"mvn%d3\\t%0, #0\";
885390075Sobrien  "
885490075Sobrien  [(set_attr "conds" "clob")
885590075Sobrien   (set_attr "length" "12")]
885690075Sobrien)
885790075Sobrien
885890075Sobrien(define_insn "movcond"
885990075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
886090075Sobrien	(if_then_else:SI
886190075Sobrien	 (match_operator 5 "arm_comparison_operator"
886290075Sobrien	  [(match_operand:SI 3 "s_register_operand" "r,r,r")
886390075Sobrien	   (match_operand:SI 4 "arm_add_operand" "rIL,rIL,rIL")])
886490075Sobrien	 (match_operand:SI 1 "arm_rhs_operand" "0,rI,?rI")
886590075Sobrien	 (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")))
886690075Sobrien   (clobber (reg:CC CC_REGNUM))]
886790075Sobrien  "TARGET_ARM"
886890075Sobrien  "*
886990075Sobrien  if (GET_CODE (operands[5]) == LT
887090075Sobrien      && (operands[4] == const0_rtx))
887190075Sobrien    {
887290075Sobrien      if (which_alternative != 1 && GET_CODE (operands[1]) == REG)
887390075Sobrien	{
887490075Sobrien	  if (operands[2] == const0_rtx)
887590075Sobrien	    return \"and\\t%0, %1, %3, asr #31\";
887690075Sobrien	  return \"ands\\t%0, %1, %3, asr #32\;movcc\\t%0, %2\";
887790075Sobrien	}
887890075Sobrien      else if (which_alternative != 0 && GET_CODE (operands[2]) == REG)
887990075Sobrien	{
888090075Sobrien	  if (operands[1] == const0_rtx)
888190075Sobrien	    return \"bic\\t%0, %2, %3, asr #31\";
888290075Sobrien	  return \"bics\\t%0, %2, %3, asr #32\;movcs\\t%0, %1\";
888390075Sobrien	}
888490075Sobrien      /* The only case that falls through to here is when both ops 1 & 2
8885132718Skan	 are constants.  */
888690075Sobrien    }
888790075Sobrien
888890075Sobrien  if (GET_CODE (operands[5]) == GE
888990075Sobrien      && (operands[4] == const0_rtx))
889090075Sobrien    {
889190075Sobrien      if (which_alternative != 1 && GET_CODE (operands[1]) == REG)
889290075Sobrien	{
889390075Sobrien	  if (operands[2] == const0_rtx)
889490075Sobrien	    return \"bic\\t%0, %1, %3, asr #31\";
889590075Sobrien	  return \"bics\\t%0, %1, %3, asr #32\;movcs\\t%0, %2\";
889690075Sobrien	}
889790075Sobrien      else if (which_alternative != 0 && GET_CODE (operands[2]) == REG)
889890075Sobrien	{
889990075Sobrien	  if (operands[1] == const0_rtx)
890090075Sobrien	    return \"and\\t%0, %2, %3, asr #31\";
890190075Sobrien	  return \"ands\\t%0, %2, %3, asr #32\;movcc\\t%0, %1\";
890290075Sobrien	}
890390075Sobrien      /* The only case that falls through to here is when both ops 1 & 2
8904132718Skan	 are constants.  */
890590075Sobrien    }
890690075Sobrien  if (GET_CODE (operands[4]) == CONST_INT
890790075Sobrien      && !const_ok_for_arm (INTVAL (operands[4])))
890890075Sobrien    output_asm_insn (\"cmn\\t%3, #%n4\", operands);
890990075Sobrien  else
891090075Sobrien    output_asm_insn (\"cmp\\t%3, %4\", operands);
891190075Sobrien  if (which_alternative != 0)
891290075Sobrien    output_asm_insn (\"mov%d5\\t%0, %1\", operands);
891390075Sobrien  if (which_alternative != 1)
891490075Sobrien    output_asm_insn (\"mov%D5\\t%0, %2\", operands);
891590075Sobrien  return \"\";
891690075Sobrien  "
891790075Sobrien  [(set_attr "conds" "clob")
891890075Sobrien   (set_attr "length" "8,8,12")]
891990075Sobrien)
892090075Sobrien
892190075Sobrien(define_insn "*ifcompare_plus_move"
892290075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
892390075Sobrien	(if_then_else:SI (match_operator 6 "arm_comparison_operator"
892490075Sobrien			  [(match_operand:SI 4 "s_register_operand" "r,r")
892590075Sobrien			   (match_operand:SI 5 "arm_add_operand" "rIL,rIL")])
892690075Sobrien			 (plus:SI
892790075Sobrien			  (match_operand:SI 2 "s_register_operand" "r,r")
892890075Sobrien			  (match_operand:SI 3 "arm_add_operand" "rIL,rIL"))
892990075Sobrien			 (match_operand:SI 1 "arm_rhs_operand" "0,?rI")))
893090075Sobrien   (clobber (reg:CC CC_REGNUM))]
893190075Sobrien  "TARGET_ARM"
893290075Sobrien  "#"
893390075Sobrien  [(set_attr "conds" "clob")
893490075Sobrien   (set_attr "length" "8,12")]
893590075Sobrien)
893690075Sobrien
893790075Sobrien(define_insn "*if_plus_move"
893890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r")
893990075Sobrien	(if_then_else:SI
894090075Sobrien	 (match_operator 4 "arm_comparison_operator"
894190075Sobrien	  [(match_operand 5 "cc_register" "") (const_int 0)])
894290075Sobrien	 (plus:SI
894390075Sobrien	  (match_operand:SI 2 "s_register_operand" "r,r,r,r")
894490075Sobrien	  (match_operand:SI 3 "arm_add_operand" "rI,L,rI,L"))
894590075Sobrien	 (match_operand:SI 1 "arm_rhs_operand" "0,0,?rI,?rI")))]
894690075Sobrien  "TARGET_ARM"
894790075Sobrien  "@
894890075Sobrien   add%d4\\t%0, %2, %3
894990075Sobrien   sub%d4\\t%0, %2, #%n3
895090075Sobrien   add%d4\\t%0, %2, %3\;mov%D4\\t%0, %1
895190075Sobrien   sub%d4\\t%0, %2, #%n3\;mov%D4\\t%0, %1"
895290075Sobrien  [(set_attr "conds" "use")
895390075Sobrien   (set_attr "length" "4,4,8,8")
895490075Sobrien   (set_attr "type" "*,*,*,*")]
895590075Sobrien)
895690075Sobrien
895790075Sobrien(define_insn "*ifcompare_move_plus"
895890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
895990075Sobrien	(if_then_else:SI (match_operator 6 "arm_comparison_operator"
896090075Sobrien			  [(match_operand:SI 4 "s_register_operand" "r,r")
896190075Sobrien			   (match_operand:SI 5 "arm_add_operand" "rIL,rIL")])
896290075Sobrien			 (match_operand:SI 1 "arm_rhs_operand" "0,?rI")
896390075Sobrien			 (plus:SI
896490075Sobrien			  (match_operand:SI 2 "s_register_operand" "r,r")
896590075Sobrien			  (match_operand:SI 3 "arm_add_operand" "rIL,rIL"))))
896690075Sobrien   (clobber (reg:CC CC_REGNUM))]
896790075Sobrien  "TARGET_ARM"
896890075Sobrien  "#"
896990075Sobrien  [(set_attr "conds" "clob")
897090075Sobrien   (set_attr "length" "8,12")]
897190075Sobrien)
897290075Sobrien
897390075Sobrien(define_insn "*if_move_plus"
897490075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r")
897590075Sobrien	(if_then_else:SI
897690075Sobrien	 (match_operator 4 "arm_comparison_operator"
897790075Sobrien	  [(match_operand 5 "cc_register" "") (const_int 0)])
897890075Sobrien	 (match_operand:SI 1 "arm_rhs_operand" "0,0,?rI,?rI")
897990075Sobrien	 (plus:SI
898090075Sobrien	  (match_operand:SI 2 "s_register_operand" "r,r,r,r")
898190075Sobrien	  (match_operand:SI 3 "arm_add_operand" "rI,L,rI,L"))))]
898290075Sobrien  "TARGET_ARM"
898390075Sobrien  "@
898490075Sobrien   add%D4\\t%0, %2, %3
898590075Sobrien   sub%D4\\t%0, %2, #%n3
898690075Sobrien   add%D4\\t%0, %2, %3\;mov%d4\\t%0, %1
898790075Sobrien   sub%D4\\t%0, %2, #%n3\;mov%d4\\t%0, %1"
898890075Sobrien  [(set_attr "conds" "use")
898990075Sobrien   (set_attr "length" "4,4,8,8")
899090075Sobrien   (set_attr "type" "*,*,*,*")]
899190075Sobrien)
899290075Sobrien
899390075Sobrien(define_insn "*ifcompare_arith_arith"
899490075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
899590075Sobrien	(if_then_else:SI (match_operator 9 "arm_comparison_operator"
899690075Sobrien			  [(match_operand:SI 5 "s_register_operand" "r")
899790075Sobrien			   (match_operand:SI 6 "arm_add_operand" "rIL")])
899890075Sobrien			 (match_operator:SI 8 "shiftable_operator"
899990075Sobrien			  [(match_operand:SI 1 "s_register_operand" "r")
900090075Sobrien			   (match_operand:SI 2 "arm_rhs_operand" "rI")])
900190075Sobrien			 (match_operator:SI 7 "shiftable_operator"
900290075Sobrien			  [(match_operand:SI 3 "s_register_operand" "r")
900390075Sobrien			   (match_operand:SI 4 "arm_rhs_operand" "rI")])))
900490075Sobrien   (clobber (reg:CC CC_REGNUM))]
900590075Sobrien  "TARGET_ARM"
900690075Sobrien  "#"
900790075Sobrien  [(set_attr "conds" "clob")
900890075Sobrien   (set_attr "length" "12")]
900990075Sobrien)
901090075Sobrien
901190075Sobrien(define_insn "*if_arith_arith"
901290075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
901390075Sobrien	(if_then_else:SI (match_operator 5 "arm_comparison_operator"
901490075Sobrien			  [(match_operand 8 "cc_register" "") (const_int 0)])
901590075Sobrien			 (match_operator:SI 6 "shiftable_operator"
901690075Sobrien			  [(match_operand:SI 1 "s_register_operand" "r")
901790075Sobrien			   (match_operand:SI 2 "arm_rhs_operand" "rI")])
901890075Sobrien			 (match_operator:SI 7 "shiftable_operator"
901990075Sobrien			  [(match_operand:SI 3 "s_register_operand" "r")
902090075Sobrien			   (match_operand:SI 4 "arm_rhs_operand" "rI")])))]
902190075Sobrien  "TARGET_ARM"
902290075Sobrien  "%I6%d5\\t%0, %1, %2\;%I7%D5\\t%0, %3, %4"
902390075Sobrien  [(set_attr "conds" "use")
902490075Sobrien   (set_attr "length" "8")]
902590075Sobrien)
902690075Sobrien
902790075Sobrien(define_insn "*ifcompare_arith_move"
902890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
902990075Sobrien	(if_then_else:SI (match_operator 6 "arm_comparison_operator"
903090075Sobrien			  [(match_operand:SI 2 "s_register_operand" "r,r")
903190075Sobrien			   (match_operand:SI 3 "arm_add_operand" "rIL,rIL")])
903290075Sobrien			 (match_operator:SI 7 "shiftable_operator"
903390075Sobrien			  [(match_operand:SI 4 "s_register_operand" "r,r")
903490075Sobrien			   (match_operand:SI 5 "arm_rhs_operand" "rI,rI")])
903590075Sobrien			 (match_operand:SI 1 "arm_rhs_operand" "0,?rI")))
903690075Sobrien   (clobber (reg:CC CC_REGNUM))]
903790075Sobrien  "TARGET_ARM"
903890075Sobrien  "*
903990075Sobrien  /* If we have an operation where (op x 0) is the identity operation and
904090075Sobrien     the conditional operator is LT or GE and we are comparing against zero and
9041132718Skan     everything is in registers then we can do this in two instructions.  */
904290075Sobrien  if (operands[3] == const0_rtx
904390075Sobrien      && GET_CODE (operands[7]) != AND
904490075Sobrien      && GET_CODE (operands[5]) == REG
904590075Sobrien      && GET_CODE (operands[1]) == REG 
904690075Sobrien      && REGNO (operands[1]) == REGNO (operands[4])
904790075Sobrien      && REGNO (operands[4]) != REGNO (operands[0]))
904890075Sobrien    {
904990075Sobrien      if (GET_CODE (operands[6]) == LT)
905090075Sobrien	return \"and\\t%0, %5, %2, asr #31\;%I7\\t%0, %4, %0\";
905190075Sobrien      else if (GET_CODE (operands[6]) == GE)
905290075Sobrien	return \"bic\\t%0, %5, %2, asr #31\;%I7\\t%0, %4, %0\";
905390075Sobrien    }
905490075Sobrien  if (GET_CODE (operands[3]) == CONST_INT
905590075Sobrien      && !const_ok_for_arm (INTVAL (operands[3])))
905690075Sobrien    output_asm_insn (\"cmn\\t%2, #%n3\", operands);
905790075Sobrien  else
905890075Sobrien    output_asm_insn (\"cmp\\t%2, %3\", operands);
905990075Sobrien  output_asm_insn (\"%I7%d6\\t%0, %4, %5\", operands);
906090075Sobrien  if (which_alternative != 0)
906190075Sobrien    return \"mov%D6\\t%0, %1\";
906290075Sobrien  return \"\";
906390075Sobrien  "
906490075Sobrien  [(set_attr "conds" "clob")
906590075Sobrien   (set_attr "length" "8,12")]
906690075Sobrien)
906790075Sobrien
906890075Sobrien(define_insn "*if_arith_move"
906990075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
907090075Sobrien	(if_then_else:SI (match_operator 4 "arm_comparison_operator"
907190075Sobrien			  [(match_operand 6 "cc_register" "") (const_int 0)])
907290075Sobrien			 (match_operator:SI 5 "shiftable_operator"
907390075Sobrien			  [(match_operand:SI 2 "s_register_operand" "r,r")
907490075Sobrien			   (match_operand:SI 3 "arm_rhs_operand" "rI,rI")])
907590075Sobrien			 (match_operand:SI 1 "arm_rhs_operand" "0,?rI")))]
907690075Sobrien  "TARGET_ARM"
907790075Sobrien  "@
907890075Sobrien   %I5%d4\\t%0, %2, %3
907990075Sobrien   %I5%d4\\t%0, %2, %3\;mov%D4\\t%0, %1"
908090075Sobrien  [(set_attr "conds" "use")
908190075Sobrien   (set_attr "length" "4,8")
908290075Sobrien   (set_attr "type" "*,*")]
908390075Sobrien)
908490075Sobrien
908590075Sobrien(define_insn "*ifcompare_move_arith"
908690075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
908790075Sobrien	(if_then_else:SI (match_operator 6 "arm_comparison_operator"
908890075Sobrien			  [(match_operand:SI 4 "s_register_operand" "r,r")
908990075Sobrien			   (match_operand:SI 5 "arm_add_operand" "rIL,rIL")])
909090075Sobrien			 (match_operand:SI 1 "arm_rhs_operand" "0,?rI")
909190075Sobrien			 (match_operator:SI 7 "shiftable_operator"
909290075Sobrien			  [(match_operand:SI 2 "s_register_operand" "r,r")
909390075Sobrien			   (match_operand:SI 3 "arm_rhs_operand" "rI,rI")])))
909490075Sobrien   (clobber (reg:CC CC_REGNUM))]
909590075Sobrien  "TARGET_ARM"
909690075Sobrien  "*
909790075Sobrien  /* If we have an operation where (op x 0) is the identity operation and
909890075Sobrien     the conditional operator is LT or GE and we are comparing against zero and
909990075Sobrien     everything is in registers then we can do this in two instructions */
910090075Sobrien  if (operands[5] == const0_rtx
910190075Sobrien      && GET_CODE (operands[7]) != AND
910290075Sobrien      && GET_CODE (operands[3]) == REG
910390075Sobrien      && GET_CODE (operands[1]) == REG 
910490075Sobrien      && REGNO (operands[1]) == REGNO (operands[2])
910590075Sobrien      && REGNO (operands[2]) != REGNO (operands[0]))
910690075Sobrien    {
910790075Sobrien      if (GET_CODE (operands[6]) == GE)
910890075Sobrien	return \"and\\t%0, %3, %4, asr #31\;%I7\\t%0, %2, %0\";
910990075Sobrien      else if (GET_CODE (operands[6]) == LT)
911090075Sobrien	return \"bic\\t%0, %3, %4, asr #31\;%I7\\t%0, %2, %0\";
911190075Sobrien    }
911290075Sobrien
911390075Sobrien  if (GET_CODE (operands[5]) == CONST_INT
911490075Sobrien      && !const_ok_for_arm (INTVAL (operands[5])))
911590075Sobrien    output_asm_insn (\"cmn\\t%4, #%n5\", operands);
911690075Sobrien  else
911790075Sobrien    output_asm_insn (\"cmp\\t%4, %5\", operands);
911890075Sobrien
911990075Sobrien  if (which_alternative != 0)
912090075Sobrien    output_asm_insn (\"mov%d6\\t%0, %1\", operands);
912190075Sobrien  return \"%I7%D6\\t%0, %2, %3\";
912290075Sobrien  "
912390075Sobrien  [(set_attr "conds" "clob")
912490075Sobrien   (set_attr "length" "8,12")]
912590075Sobrien)
912690075Sobrien
912790075Sobrien(define_insn "*if_move_arith"
912890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
912990075Sobrien	(if_then_else:SI
913090075Sobrien	 (match_operator 4 "arm_comparison_operator"
913190075Sobrien	  [(match_operand 6 "cc_register" "") (const_int 0)])
913290075Sobrien	 (match_operand:SI 1 "arm_rhs_operand" "0,?rI")
913390075Sobrien	 (match_operator:SI 5 "shiftable_operator"
913490075Sobrien	  [(match_operand:SI 2 "s_register_operand" "r,r")
913590075Sobrien	   (match_operand:SI 3 "arm_rhs_operand" "rI,rI")])))]
913690075Sobrien  "TARGET_ARM"
913790075Sobrien  "@
913890075Sobrien   %I5%D4\\t%0, %2, %3
913990075Sobrien   %I5%D4\\t%0, %2, %3\;mov%d4\\t%0, %1"
914090075Sobrien  [(set_attr "conds" "use")
914190075Sobrien   (set_attr "length" "4,8")
914290075Sobrien   (set_attr "type" "*,*")]
914390075Sobrien)
914490075Sobrien
914590075Sobrien(define_insn "*ifcompare_move_not"
914690075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
914790075Sobrien	(if_then_else:SI
914890075Sobrien	 (match_operator 5 "arm_comparison_operator"
914990075Sobrien	  [(match_operand:SI 3 "s_register_operand" "r,r")
915090075Sobrien	   (match_operand:SI 4 "arm_add_operand" "rIL,rIL")])
915190075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rIK")
915290075Sobrien	 (not:SI
915390075Sobrien	  (match_operand:SI 2 "s_register_operand" "r,r"))))
915490075Sobrien   (clobber (reg:CC CC_REGNUM))]
915590075Sobrien  "TARGET_ARM"
915690075Sobrien  "#"
915790075Sobrien  [(set_attr "conds" "clob")
915890075Sobrien   (set_attr "length" "8,12")]
915990075Sobrien)
916090075Sobrien
916190075Sobrien(define_insn "*if_move_not"
916290075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
916390075Sobrien	(if_then_else:SI
916490075Sobrien	 (match_operator 4 "arm_comparison_operator"
916590075Sobrien	  [(match_operand 3 "cc_register" "") (const_int 0)])
916690075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rI,K")
916790075Sobrien	 (not:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))))]
916890075Sobrien  "TARGET_ARM"
916990075Sobrien  "@
917090075Sobrien   mvn%D4\\t%0, %2
917190075Sobrien   mov%d4\\t%0, %1\;mvn%D4\\t%0, %2
917290075Sobrien   mvn%d4\\t%0, #%B1\;mvn%D4\\t%0, %2"
917390075Sobrien  [(set_attr "conds" "use")
917490075Sobrien   (set_attr "length" "4,8,8")]
917590075Sobrien)
917690075Sobrien
917790075Sobrien(define_insn "*ifcompare_not_move"
917890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
917990075Sobrien	(if_then_else:SI 
918090075Sobrien	 (match_operator 5 "arm_comparison_operator"
918190075Sobrien	  [(match_operand:SI 3 "s_register_operand" "r,r")
918290075Sobrien	   (match_operand:SI 4 "arm_add_operand" "rIL,rIL")])
918390075Sobrien	 (not:SI
918490075Sobrien	  (match_operand:SI 2 "s_register_operand" "r,r"))
918590075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rIK")))
918690075Sobrien   (clobber (reg:CC CC_REGNUM))]
918790075Sobrien  "TARGET_ARM"
918890075Sobrien  "#"
918990075Sobrien  [(set_attr "conds" "clob")
919090075Sobrien   (set_attr "length" "8,12")]
919190075Sobrien)
919290075Sobrien
919390075Sobrien(define_insn "*if_not_move"
919490075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
919590075Sobrien	(if_then_else:SI
919690075Sobrien	 (match_operator 4 "arm_comparison_operator"
919790075Sobrien	  [(match_operand 3 "cc_register" "") (const_int 0)])
919890075Sobrien	 (not:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))
919990075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))]
920090075Sobrien  "TARGET_ARM"
920190075Sobrien  "@
920290075Sobrien   mvn%d4\\t%0, %2
920390075Sobrien   mov%D4\\t%0, %1\;mvn%d4\\t%0, %2
920490075Sobrien   mvn%D4\\t%0, #%B1\;mvn%d4\\t%0, %2"
920590075Sobrien  [(set_attr "conds" "use")
920690075Sobrien   (set_attr "length" "4,8,8")]
920790075Sobrien)
920890075Sobrien
920990075Sobrien(define_insn "*ifcompare_shift_move"
921090075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
921190075Sobrien	(if_then_else:SI
921290075Sobrien	 (match_operator 6 "arm_comparison_operator"
921390075Sobrien	  [(match_operand:SI 4 "s_register_operand" "r,r")
921490075Sobrien	   (match_operand:SI 5 "arm_add_operand" "rIL,rIL")])
921590075Sobrien	 (match_operator:SI 7 "shift_operator"
921690075Sobrien	  [(match_operand:SI 2 "s_register_operand" "r,r")
921790075Sobrien	   (match_operand:SI 3 "arm_rhs_operand" "rM,rM")])
921890075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rIK")))
921990075Sobrien   (clobber (reg:CC CC_REGNUM))]
922090075Sobrien  "TARGET_ARM"
922190075Sobrien  "#"
922290075Sobrien  [(set_attr "conds" "clob")
922390075Sobrien   (set_attr "length" "8,12")]
922490075Sobrien)
922590075Sobrien
922690075Sobrien(define_insn "*if_shift_move"
922790075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
922890075Sobrien	(if_then_else:SI
922990075Sobrien	 (match_operator 5 "arm_comparison_operator"
923090075Sobrien	  [(match_operand 6 "cc_register" "") (const_int 0)])
923190075Sobrien	 (match_operator:SI 4 "shift_operator"
923290075Sobrien	  [(match_operand:SI 2 "s_register_operand" "r,r,r")
923390075Sobrien	   (match_operand:SI 3 "arm_rhs_operand" "rM,rM,rM")])
923490075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))]
923590075Sobrien  "TARGET_ARM"
923690075Sobrien  "@
923790075Sobrien   mov%d5\\t%0, %2%S4
923890075Sobrien   mov%D5\\t%0, %1\;mov%d5\\t%0, %2%S4
923990075Sobrien   mvn%D5\\t%0, #%B1\;mov%d5\\t%0, %2%S4"
924090075Sobrien  [(set_attr "conds" "use")
924190075Sobrien   (set_attr "shift" "2")
9242169689Skan   (set_attr "length" "4,8,8")
9243169689Skan   (set (attr "type") (if_then_else (match_operand 3 "const_int_operand" "")
9244169689Skan		      (const_string "alu_shift")
9245169689Skan		      (const_string "alu_shift_reg")))]
924690075Sobrien)
924790075Sobrien
924890075Sobrien(define_insn "*ifcompare_move_shift"
924990075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
925090075Sobrien	(if_then_else:SI
925190075Sobrien	 (match_operator 6 "arm_comparison_operator"
925290075Sobrien	  [(match_operand:SI 4 "s_register_operand" "r,r")
925390075Sobrien	   (match_operand:SI 5 "arm_add_operand" "rIL,rIL")])
925490075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rIK")
925590075Sobrien	 (match_operator:SI 7 "shift_operator"
925690075Sobrien	  [(match_operand:SI 2 "s_register_operand" "r,r")
925790075Sobrien	   (match_operand:SI 3 "arm_rhs_operand" "rM,rM")])))
925890075Sobrien   (clobber (reg:CC CC_REGNUM))]
925990075Sobrien  "TARGET_ARM"
926090075Sobrien  "#"
926190075Sobrien  [(set_attr "conds" "clob")
926290075Sobrien   (set_attr "length" "8,12")]
926390075Sobrien)
926490075Sobrien
926590075Sobrien(define_insn "*if_move_shift"
926690075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
926790075Sobrien	(if_then_else:SI
926890075Sobrien	 (match_operator 5 "arm_comparison_operator"
926990075Sobrien	  [(match_operand 6 "cc_register" "") (const_int 0)])
927090075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rI,K")
927190075Sobrien	 (match_operator:SI 4 "shift_operator"
927290075Sobrien	  [(match_operand:SI 2 "s_register_operand" "r,r,r")
927390075Sobrien	   (match_operand:SI 3 "arm_rhs_operand" "rM,rM,rM")])))]
927490075Sobrien  "TARGET_ARM"
927590075Sobrien  "@
927690075Sobrien   mov%D5\\t%0, %2%S4
927790075Sobrien   mov%d5\\t%0, %1\;mov%D5\\t%0, %2%S4
927890075Sobrien   mvn%d5\\t%0, #%B1\;mov%D5\\t%0, %2%S4"
927990075Sobrien  [(set_attr "conds" "use")
928090075Sobrien   (set_attr "shift" "2")
9281169689Skan   (set_attr "length" "4,8,8")
9282169689Skan   (set (attr "type") (if_then_else (match_operand 3 "const_int_operand" "")
9283169689Skan		      (const_string "alu_shift")
9284169689Skan		      (const_string "alu_shift_reg")))]
928590075Sobrien)
928690075Sobrien
928790075Sobrien(define_insn "*ifcompare_shift_shift"
928890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
928990075Sobrien	(if_then_else:SI
929090075Sobrien	 (match_operator 7 "arm_comparison_operator"
929190075Sobrien	  [(match_operand:SI 5 "s_register_operand" "r")
929290075Sobrien	   (match_operand:SI 6 "arm_add_operand" "rIL")])
929390075Sobrien	 (match_operator:SI 8 "shift_operator"
929490075Sobrien	  [(match_operand:SI 1 "s_register_operand" "r")
929590075Sobrien	   (match_operand:SI 2 "arm_rhs_operand" "rM")])
929690075Sobrien	 (match_operator:SI 9 "shift_operator"
929790075Sobrien	  [(match_operand:SI 3 "s_register_operand" "r")
929890075Sobrien	   (match_operand:SI 4 "arm_rhs_operand" "rM")])))
929990075Sobrien   (clobber (reg:CC CC_REGNUM))]
930090075Sobrien  "TARGET_ARM"
930190075Sobrien  "#"
930290075Sobrien  [(set_attr "conds" "clob")
930390075Sobrien   (set_attr "length" "12")]
930490075Sobrien)
930590075Sobrien
930690075Sobrien(define_insn "*if_shift_shift"
930790075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
930890075Sobrien	(if_then_else:SI
930990075Sobrien	 (match_operator 5 "arm_comparison_operator"
931090075Sobrien	  [(match_operand 8 "cc_register" "") (const_int 0)])
931190075Sobrien	 (match_operator:SI 6 "shift_operator"
931290075Sobrien	  [(match_operand:SI 1 "s_register_operand" "r")
931390075Sobrien	   (match_operand:SI 2 "arm_rhs_operand" "rM")])
931490075Sobrien	 (match_operator:SI 7 "shift_operator"
931590075Sobrien	  [(match_operand:SI 3 "s_register_operand" "r")
931690075Sobrien	   (match_operand:SI 4 "arm_rhs_operand" "rM")])))]
931790075Sobrien  "TARGET_ARM"
931890075Sobrien  "mov%d5\\t%0, %1%S6\;mov%D5\\t%0, %3%S7"
931990075Sobrien  [(set_attr "conds" "use")
932090075Sobrien   (set_attr "shift" "1")
9321169689Skan   (set_attr "length" "8")
9322169689Skan   (set (attr "type") (if_then_else
9323169689Skan		        (and (match_operand 2 "const_int_operand" "")
9324169689Skan                             (match_operand 4 "const_int_operand" ""))
9325169689Skan		      (const_string "alu_shift")
9326169689Skan		      (const_string "alu_shift_reg")))]
932790075Sobrien)
932890075Sobrien
932990075Sobrien(define_insn "*ifcompare_not_arith"
933090075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
933190075Sobrien	(if_then_else:SI
933290075Sobrien	 (match_operator 6 "arm_comparison_operator"
933390075Sobrien	  [(match_operand:SI 4 "s_register_operand" "r")
933490075Sobrien	   (match_operand:SI 5 "arm_add_operand" "rIL")])
933590075Sobrien	 (not:SI (match_operand:SI 1 "s_register_operand" "r"))
933690075Sobrien	 (match_operator:SI 7 "shiftable_operator"
933790075Sobrien	  [(match_operand:SI 2 "s_register_operand" "r")
933890075Sobrien	   (match_operand:SI 3 "arm_rhs_operand" "rI")])))
933990075Sobrien   (clobber (reg:CC CC_REGNUM))]
934090075Sobrien  "TARGET_ARM"
934190075Sobrien  "#"
934290075Sobrien  [(set_attr "conds" "clob")
934390075Sobrien   (set_attr "length" "12")]
934490075Sobrien)
934590075Sobrien
934690075Sobrien(define_insn "*if_not_arith"
934790075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
934890075Sobrien	(if_then_else:SI
934990075Sobrien	 (match_operator 5 "arm_comparison_operator"
935090075Sobrien	  [(match_operand 4 "cc_register" "") (const_int 0)])
935190075Sobrien	 (not:SI (match_operand:SI 1 "s_register_operand" "r"))
935290075Sobrien	 (match_operator:SI 6 "shiftable_operator"
935390075Sobrien	  [(match_operand:SI 2 "s_register_operand" "r")
935490075Sobrien	   (match_operand:SI 3 "arm_rhs_operand" "rI")])))]
935590075Sobrien  "TARGET_ARM"
935690075Sobrien  "mvn%d5\\t%0, %1\;%I6%D5\\t%0, %2, %3"
935790075Sobrien  [(set_attr "conds" "use")
935890075Sobrien   (set_attr "length" "8")]
935990075Sobrien)
936090075Sobrien
936190075Sobrien(define_insn "*ifcompare_arith_not"
936290075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
936390075Sobrien	(if_then_else:SI
936490075Sobrien	 (match_operator 6 "arm_comparison_operator"
936590075Sobrien	  [(match_operand:SI 4 "s_register_operand" "r")
936690075Sobrien	   (match_operand:SI 5 "arm_add_operand" "rIL")])
936790075Sobrien	 (match_operator:SI 7 "shiftable_operator"
936890075Sobrien	  [(match_operand:SI 2 "s_register_operand" "r")
936990075Sobrien	   (match_operand:SI 3 "arm_rhs_operand" "rI")])
937090075Sobrien	 (not:SI (match_operand:SI 1 "s_register_operand" "r"))))
937190075Sobrien   (clobber (reg:CC CC_REGNUM))]
937290075Sobrien  "TARGET_ARM"
937390075Sobrien  "#"
937490075Sobrien  [(set_attr "conds" "clob")
937590075Sobrien   (set_attr "length" "12")]
937690075Sobrien)
937790075Sobrien
937890075Sobrien(define_insn "*if_arith_not"
937990075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
938090075Sobrien	(if_then_else:SI
938190075Sobrien	 (match_operator 5 "arm_comparison_operator"
938290075Sobrien	  [(match_operand 4 "cc_register" "") (const_int 0)])
938390075Sobrien	 (match_operator:SI 6 "shiftable_operator"
938490075Sobrien	  [(match_operand:SI 2 "s_register_operand" "r")
938590075Sobrien	   (match_operand:SI 3 "arm_rhs_operand" "rI")])
938690075Sobrien	 (not:SI (match_operand:SI 1 "s_register_operand" "r"))))]
938790075Sobrien  "TARGET_ARM"
938890075Sobrien  "mvn%D5\\t%0, %1\;%I6%d5\\t%0, %2, %3"
938990075Sobrien  [(set_attr "conds" "use")
939090075Sobrien   (set_attr "length" "8")]
939190075Sobrien)
939290075Sobrien
939390075Sobrien(define_insn "*ifcompare_neg_move"
939490075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
939590075Sobrien	(if_then_else:SI
939690075Sobrien	 (match_operator 5 "arm_comparison_operator"
939790075Sobrien	  [(match_operand:SI 3 "s_register_operand" "r,r")
939890075Sobrien	   (match_operand:SI 4 "arm_add_operand" "rIL,rIL")])
939990075Sobrien	 (neg:SI (match_operand:SI 2 "s_register_operand" "r,r"))
940090075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rIK")))
940190075Sobrien   (clobber (reg:CC CC_REGNUM))]
940290075Sobrien  "TARGET_ARM"
940390075Sobrien  "#"
940490075Sobrien  [(set_attr "conds" "clob")
940590075Sobrien   (set_attr "length" "8,12")]
940690075Sobrien)
940790075Sobrien
940890075Sobrien(define_insn "*if_neg_move"
940990075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
941090075Sobrien	(if_then_else:SI
941190075Sobrien	 (match_operator 4 "arm_comparison_operator"
941290075Sobrien	  [(match_operand 3 "cc_register" "") (const_int 0)])
941390075Sobrien	 (neg:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))
941490075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))]
941590075Sobrien  "TARGET_ARM"
941690075Sobrien  "@
941790075Sobrien   rsb%d4\\t%0, %2, #0
941890075Sobrien   mov%D4\\t%0, %1\;rsb%d4\\t%0, %2, #0
941990075Sobrien   mvn%D4\\t%0, #%B1\;rsb%d4\\t%0, %2, #0"
942090075Sobrien  [(set_attr "conds" "use")
942190075Sobrien   (set_attr "length" "4,8,8")]
942290075Sobrien)
942390075Sobrien
942490075Sobrien(define_insn "*ifcompare_move_neg"
942590075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
942690075Sobrien	(if_then_else:SI
942790075Sobrien	 (match_operator 5 "arm_comparison_operator"
942890075Sobrien	  [(match_operand:SI 3 "s_register_operand" "r,r")
942990075Sobrien	   (match_operand:SI 4 "arm_add_operand" "rIL,rIL")])
943090075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rIK")
943190075Sobrien	 (neg:SI (match_operand:SI 2 "s_register_operand" "r,r"))))
943290075Sobrien   (clobber (reg:CC CC_REGNUM))]
943390075Sobrien  "TARGET_ARM"
943490075Sobrien  "#"
943590075Sobrien  [(set_attr "conds" "clob")
943690075Sobrien   (set_attr "length" "8,12")]
943790075Sobrien)
943890075Sobrien
943990075Sobrien(define_insn "*if_move_neg"
944090075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
944190075Sobrien	(if_then_else:SI
944290075Sobrien	 (match_operator 4 "arm_comparison_operator"
944390075Sobrien	  [(match_operand 3 "cc_register" "") (const_int 0)])
944490075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rI,K")
944590075Sobrien	 (neg:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))))]
944690075Sobrien  "TARGET_ARM"
944790075Sobrien  "@
944890075Sobrien   rsb%D4\\t%0, %2, #0
944990075Sobrien   mov%d4\\t%0, %1\;rsb%D4\\t%0, %2, #0
945090075Sobrien   mvn%d4\\t%0, #%B1\;rsb%D4\\t%0, %2, #0"
945190075Sobrien  [(set_attr "conds" "use")
945290075Sobrien   (set_attr "length" "4,8,8")]
945390075Sobrien)
945490075Sobrien
945590075Sobrien(define_insn "*arith_adjacentmem"
945690075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
945790075Sobrien	(match_operator:SI 1 "shiftable_operator"
945890075Sobrien	 [(match_operand:SI 2 "memory_operand" "m")
945990075Sobrien	  (match_operand:SI 3 "memory_operand" "m")]))
946090075Sobrien   (clobber (match_scratch:SI 4 "=r"))]
946190075Sobrien  "TARGET_ARM && adjacent_mem_locations (operands[2], operands[3])"
946290075Sobrien  "*
946390075Sobrien  {
946490075Sobrien    rtx ldm[3];
946590075Sobrien    rtx arith[4];
9466169689Skan    rtx base_reg;
9467169689Skan    HOST_WIDE_INT val1 = 0, val2 = 0;
946890075Sobrien
946990075Sobrien    if (REGNO (operands[0]) > REGNO (operands[4]))
947090075Sobrien      {
947190075Sobrien	ldm[1] = operands[4];
947290075Sobrien	ldm[2] = operands[0];
947390075Sobrien      }
947490075Sobrien    else
947590075Sobrien      {
947690075Sobrien	ldm[1] = operands[0];
947790075Sobrien	ldm[2] = operands[4];
947890075Sobrien      }
9479169689Skan
9480169689Skan    base_reg = XEXP (operands[2], 0);
9481169689Skan
9482169689Skan    if (!REG_P (base_reg))
9483169689Skan      {
9484169689Skan	val1 = INTVAL (XEXP (base_reg, 1));
9485169689Skan	base_reg = XEXP (base_reg, 0);
9486169689Skan      }
9487169689Skan
9488169689Skan    if (!REG_P (XEXP (operands[3], 0)))
948990075Sobrien      val2 = INTVAL (XEXP (XEXP (operands[3], 0), 1));
9490169689Skan
949190075Sobrien    arith[0] = operands[0];
949290075Sobrien    arith[3] = operands[1];
9493169689Skan
949490075Sobrien    if (val1 < val2)
949590075Sobrien      {
949690075Sobrien	arith[1] = ldm[1];
949790075Sobrien	arith[2] = ldm[2];
949890075Sobrien      }
949990075Sobrien    else
950090075Sobrien      {
950190075Sobrien	arith[1] = ldm[2];
950290075Sobrien	arith[2] = ldm[1];
950390075Sobrien      }
9504169689Skan
9505169689Skan    ldm[0] = base_reg;
9506169689Skan    if (val1 !=0 && val2 != 0)
950790075Sobrien      {
950890075Sobrien	rtx ops[3];
9509169689Skan
9510169689Skan	if (val1 == 4 || val2 == 4)
9511169689Skan	  /* Other val must be 8, since we know they are adjacent and neither
9512169689Skan	     is zero.  */
9513169689Skan	  output_asm_insn (\"ldm%?ib\\t%0, {%1, %2}\", ldm);
9514169689Skan	else if (const_ok_for_arm (val1) || const_ok_for_arm (-val1))
9515169689Skan	  {
9516169689Skan	    ldm[0] = ops[0] = operands[4];
9517169689Skan	    ops[1] = base_reg;
9518169689Skan	    ops[2] = GEN_INT (val1);
9519169689Skan	    output_add_immediate (ops);
9520169689Skan	    if (val1 < val2)
9521169689Skan	      output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm);
9522169689Skan	    else
9523169689Skan	      output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm);
9524169689Skan	  }
952590075Sobrien	else
9526169689Skan	  {
9527169689Skan	    /* Offset is out of range for a single add, so use two ldr.  */
9528169689Skan	    ops[0] = ldm[1];
9529169689Skan	    ops[1] = base_reg;
9530169689Skan	    ops[2] = GEN_INT (val1);
9531169689Skan	    output_asm_insn (\"ldr%?\\t%0, [%1, %2]\", ops);
9532169689Skan	    ops[0] = ldm[2];
9533169689Skan	    ops[2] = GEN_INT (val2);
9534169689Skan	    output_asm_insn (\"ldr%?\\t%0, [%1, %2]\", ops);
9535169689Skan	  }
953690075Sobrien      }
9537169689Skan    else if (val1 != 0)
953890075Sobrien      {
953990075Sobrien	if (val1 < val2)
954090075Sobrien	  output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm);
954190075Sobrien	else
954290075Sobrien	  output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm);
954390075Sobrien      }
954490075Sobrien    else
954590075Sobrien      {
954690075Sobrien	if (val1 < val2)
954790075Sobrien	  output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm);
954890075Sobrien	else
954990075Sobrien	  output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm);
955090075Sobrien      }
955190075Sobrien    output_asm_insn (\"%I3%?\\t%0, %1, %2\", arith);
955290075Sobrien    return \"\";
955390075Sobrien  }"
955490075Sobrien  [(set_attr "length" "12")
955590075Sobrien   (set_attr "predicable" "yes")
9556169689Skan   (set_attr "type" "load1")]
955790075Sobrien)
955890075Sobrien
955990075Sobrien; This pattern is never tried by combine, so do it as a peephole
956090075Sobrien
956190075Sobrien(define_peephole2
9562169689Skan  [(set (match_operand:SI 0 "arm_general_register_operand" "")
9563169689Skan	(match_operand:SI 1 "arm_general_register_operand" ""))
956490075Sobrien   (set (reg:CC CC_REGNUM)
956590075Sobrien	(compare:CC (match_dup 1) (const_int 0)))]
9566169689Skan  "TARGET_ARM"
956790075Sobrien  [(parallel [(set (reg:CC CC_REGNUM) (compare:CC (match_dup 1) (const_int 0)))
956890075Sobrien	      (set (match_dup 0) (match_dup 1))])]
956990075Sobrien  ""
957090075Sobrien)
957190075Sobrien
957290075Sobrien; Peepholes to spot possible load- and store-multiples, if the ordering is
957390075Sobrien; reversed, check that the memory references aren't volatile.
957490075Sobrien
957590075Sobrien(define_peephole
957690075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
957790075Sobrien        (match_operand:SI 4 "memory_operand" "m"))
957890075Sobrien   (set (match_operand:SI 1 "s_register_operand" "=r")
957990075Sobrien        (match_operand:SI 5 "memory_operand" "m"))
958090075Sobrien   (set (match_operand:SI 2 "s_register_operand" "=r")
958190075Sobrien        (match_operand:SI 6 "memory_operand" "m"))
958290075Sobrien   (set (match_operand:SI 3 "s_register_operand" "=r")
958390075Sobrien        (match_operand:SI 7 "memory_operand" "m"))]
958490075Sobrien  "TARGET_ARM && load_multiple_sequence (operands, 4, NULL, NULL, NULL)"
958590075Sobrien  "*
958690075Sobrien  return emit_ldm_seq (operands, 4);
958790075Sobrien  "
958890075Sobrien)
958990075Sobrien
959090075Sobrien(define_peephole
959190075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
959290075Sobrien        (match_operand:SI 3 "memory_operand" "m"))
959390075Sobrien   (set (match_operand:SI 1 "s_register_operand" "=r")
959490075Sobrien        (match_operand:SI 4 "memory_operand" "m"))
959590075Sobrien   (set (match_operand:SI 2 "s_register_operand" "=r")
959690075Sobrien        (match_operand:SI 5 "memory_operand" "m"))]
959790075Sobrien  "TARGET_ARM && load_multiple_sequence (operands, 3, NULL, NULL, NULL)"
959890075Sobrien  "*
959990075Sobrien  return emit_ldm_seq (operands, 3);
960090075Sobrien  "
960190075Sobrien)
960290075Sobrien
960390075Sobrien(define_peephole
960490075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
960590075Sobrien        (match_operand:SI 2 "memory_operand" "m"))
960690075Sobrien   (set (match_operand:SI 1 "s_register_operand" "=r")
960790075Sobrien        (match_operand:SI 3 "memory_operand" "m"))]
960890075Sobrien  "TARGET_ARM && load_multiple_sequence (operands, 2, NULL, NULL, NULL)"
960990075Sobrien  "*
961090075Sobrien  return emit_ldm_seq (operands, 2);
961190075Sobrien  "
961290075Sobrien)
961390075Sobrien
961490075Sobrien(define_peephole
961590075Sobrien  [(set (match_operand:SI 4 "memory_operand" "=m")
961690075Sobrien        (match_operand:SI 0 "s_register_operand" "r"))
961790075Sobrien   (set (match_operand:SI 5 "memory_operand" "=m")
961890075Sobrien        (match_operand:SI 1 "s_register_operand" "r"))
961990075Sobrien   (set (match_operand:SI 6 "memory_operand" "=m")
962090075Sobrien        (match_operand:SI 2 "s_register_operand" "r"))
962190075Sobrien   (set (match_operand:SI 7 "memory_operand" "=m")
962290075Sobrien        (match_operand:SI 3 "s_register_operand" "r"))]
962390075Sobrien  "TARGET_ARM && store_multiple_sequence (operands, 4, NULL, NULL, NULL)"
962490075Sobrien  "*
962590075Sobrien  return emit_stm_seq (operands, 4);
962690075Sobrien  "
962790075Sobrien)
962890075Sobrien
962990075Sobrien(define_peephole
963090075Sobrien  [(set (match_operand:SI 3 "memory_operand" "=m")
963190075Sobrien        (match_operand:SI 0 "s_register_operand" "r"))
963290075Sobrien   (set (match_operand:SI 4 "memory_operand" "=m")
963390075Sobrien        (match_operand:SI 1 "s_register_operand" "r"))
963490075Sobrien   (set (match_operand:SI 5 "memory_operand" "=m")
963590075Sobrien        (match_operand:SI 2 "s_register_operand" "r"))]
963690075Sobrien  "TARGET_ARM && store_multiple_sequence (operands, 3, NULL, NULL, NULL)"
963790075Sobrien  "*
963890075Sobrien  return emit_stm_seq (operands, 3);
963990075Sobrien  "
964090075Sobrien)
964190075Sobrien
964290075Sobrien(define_peephole
964390075Sobrien  [(set (match_operand:SI 2 "memory_operand" "=m")
964490075Sobrien        (match_operand:SI 0 "s_register_operand" "r"))
964590075Sobrien   (set (match_operand:SI 3 "memory_operand" "=m")
964690075Sobrien        (match_operand:SI 1 "s_register_operand" "r"))]
964790075Sobrien  "TARGET_ARM && store_multiple_sequence (operands, 2, NULL, NULL, NULL)"
964890075Sobrien  "*
964990075Sobrien  return emit_stm_seq (operands, 2);
965090075Sobrien  "
965190075Sobrien)
965290075Sobrien
965390075Sobrien(define_split
965490075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
965590075Sobrien	(and:SI (ge:SI (match_operand:SI 1 "s_register_operand" "")
965690075Sobrien		       (const_int 0))
965790075Sobrien		(neg:SI (match_operator:SI 2 "arm_comparison_operator"
965890075Sobrien			 [(match_operand:SI 3 "s_register_operand" "")
965990075Sobrien			  (match_operand:SI 4 "arm_rhs_operand" "")]))))
966090075Sobrien   (clobber (match_operand:SI 5 "s_register_operand" ""))]
966190075Sobrien  "TARGET_ARM"
966290075Sobrien  [(set (match_dup 5) (not:SI (ashiftrt:SI (match_dup 1) (const_int 31))))
966390075Sobrien   (set (match_dup 0) (and:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)])
966490075Sobrien			      (match_dup 5)))]
966590075Sobrien  ""
966690075Sobrien)
966790075Sobrien
966890075Sobrien;; This split can be used because CC_Z mode implies that the following
966990075Sobrien;; branch will be an equality, or an unsigned inequality, so the sign
967090075Sobrien;; extension is not needed.
967190075Sobrien
967290075Sobrien(define_split
967390075Sobrien  [(set (reg:CC_Z CC_REGNUM)
967490075Sobrien	(compare:CC_Z
967590075Sobrien	 (ashift:SI (subreg:SI (match_operand:QI 0 "memory_operand" "") 0)
967690075Sobrien		    (const_int 24))
967790075Sobrien	 (match_operand 1 "const_int_operand" "")))
967890075Sobrien   (clobber (match_scratch:SI 2 ""))]
967990075Sobrien  "TARGET_ARM
968090075Sobrien   && (((unsigned HOST_WIDE_INT) INTVAL (operands[1]))
968190075Sobrien       == (((unsigned HOST_WIDE_INT) INTVAL (operands[1])) >> 24) << 24)"
968290075Sobrien  [(set (match_dup 2) (zero_extend:SI (match_dup 0)))
968390075Sobrien   (set (reg:CC CC_REGNUM) (compare:CC (match_dup 2) (match_dup 1)))]
968490075Sobrien  "
968590075Sobrien  operands[1] = GEN_INT (((unsigned long) INTVAL (operands[1])) >> 24);
968690075Sobrien  "
968790075Sobrien)
968890075Sobrien
968990075Sobrien(define_expand "prologue"
969090075Sobrien  [(clobber (const_int 0))]
969190075Sobrien  "TARGET_EITHER"
969290075Sobrien  "if (TARGET_ARM)
969390075Sobrien     arm_expand_prologue ();
969490075Sobrien   else
969590075Sobrien     thumb_expand_prologue ();
969690075Sobrien  DONE;
969790075Sobrien  "
969890075Sobrien)
969990075Sobrien
970090075Sobrien(define_expand "epilogue"
9701169689Skan  [(clobber (const_int 0))]
970290075Sobrien  "TARGET_EITHER"
970390075Sobrien  "
9704169689Skan  if (current_function_calls_eh_return)
9705169689Skan    emit_insn (gen_prologue_use (gen_rtx_REG (Pmode, 2)));
970690075Sobrien  if (TARGET_THUMB)
970790075Sobrien    thumb_expand_epilogue ();
970890075Sobrien  else if (USE_RETURN_INSN (FALSE))
970990075Sobrien    {
971090075Sobrien      emit_jump_insn (gen_return ());
971190075Sobrien      DONE;
971290075Sobrien    }
971390075Sobrien  emit_jump_insn (gen_rtx_UNSPEC_VOLATILE (VOIDmode,
971490075Sobrien	gen_rtvec (1,
971590075Sobrien		gen_rtx_RETURN (VOIDmode)),
971690075Sobrien	VUNSPEC_EPILOGUE));
971790075Sobrien  DONE;
971890075Sobrien  "
971990075Sobrien)
972090075Sobrien
9721117395Skan;; Note - although unspec_volatile's USE all hard registers,
9722117395Skan;; USEs are ignored after relaod has completed.  Thus we need
9723117395Skan;; to add an unspec of the link register to ensure that flow
9724117395Skan;; does not think that it is unused by the sibcall branch that
9725117395Skan;; will replace the standard function epilogue.
972690075Sobrien(define_insn "sibcall_epilogue"
9727117395Skan  [(parallel [(unspec:SI [(reg:SI LR_REGNUM)] UNSPEC_PROLOGUE_USE)
9728117395Skan              (unspec_volatile [(return)] VUNSPEC_EPILOGUE)])]
972990075Sobrien  "TARGET_ARM"
973090075Sobrien  "*
9731132718Skan  if (use_return_insn (FALSE, next_nonnote_insn (insn)))
9732117395Skan    return output_return_instruction (const_true_rtx, FALSE, FALSE);
9733132718Skan  return arm_output_epilogue (next_nonnote_insn (insn));
973490075Sobrien  "
973590075Sobrien;; Length is absolute worst case
973690075Sobrien  [(set_attr "length" "44")
9737117395Skan   (set_attr "type" "block")
9738117395Skan   ;; We don't clobber the conditions, but the potential length of this
9739117395Skan   ;; operation is sufficient to make conditionalizing the sequence 
9740117395Skan   ;; unlikely to be profitable.
9741117395Skan   (set_attr "conds" "clob")]
974290075Sobrien)
974390075Sobrien
974490075Sobrien(define_insn "*epilogue_insns"
974590075Sobrien  [(unspec_volatile [(return)] VUNSPEC_EPILOGUE)]
974690075Sobrien  "TARGET_EITHER"
974790075Sobrien  "*
974890075Sobrien  if (TARGET_ARM)
9749132718Skan    return arm_output_epilogue (NULL);
975090075Sobrien  else /* TARGET_THUMB */
975190075Sobrien    return thumb_unexpanded_epilogue ();
975290075Sobrien  "
975390075Sobrien  ; Length is absolute worst case
975490075Sobrien  [(set_attr "length" "44")
9755117395Skan   (set_attr "type" "block")
9756117395Skan   ;; We don't clobber the conditions, but the potential length of this
9757117395Skan   ;; operation is sufficient to make conditionalizing the sequence 
9758117395Skan   ;; unlikely to be profitable.
9759117395Skan   (set_attr "conds" "clob")]
976090075Sobrien)
976190075Sobrien
976290075Sobrien(define_expand "eh_epilogue"
9763132718Skan  [(use (match_operand:SI 0 "register_operand" ""))
9764132718Skan   (use (match_operand:SI 1 "register_operand" ""))
9765132718Skan   (use (match_operand:SI 2 "register_operand" ""))]
976690075Sobrien  "TARGET_EITHER"
976790075Sobrien  "
976890075Sobrien  {
976990075Sobrien    cfun->machine->eh_epilogue_sp_ofs = operands[1];
977090075Sobrien    if (GET_CODE (operands[2]) != REG || REGNO (operands[2]) != 2)
977190075Sobrien      {
977290075Sobrien	rtx ra = gen_rtx_REG (Pmode, 2);
977390075Sobrien
977490075Sobrien	emit_move_insn (ra, operands[2]);
977590075Sobrien	operands[2] = ra;
977690075Sobrien      }
977790075Sobrien    /* This is a hack -- we may have crystalized the function type too
977890075Sobrien       early.  */
977990075Sobrien    cfun->machine->func_type = 0;
978090075Sobrien  }"
978190075Sobrien)
978290075Sobrien
978390075Sobrien;; This split is only used during output to reduce the number of patterns
978490075Sobrien;; that need assembler instructions adding to them.  We allowed the setting
978590075Sobrien;; of the conditions to be implicit during rtl generation so that
978690075Sobrien;; the conditional compare patterns would work.  However this conflicts to
978790075Sobrien;; some extent with the conditional data operations, so we have to split them
978890075Sobrien;; up again here.
978990075Sobrien
979090075Sobrien(define_split
979190075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
979290075Sobrien	(if_then_else:SI (match_operator 1 "arm_comparison_operator"
979390075Sobrien			  [(match_operand 2 "" "") (match_operand 3 "" "")])
979490075Sobrien			 (match_dup 0)
979590075Sobrien			 (match_operand 4 "" "")))
979690075Sobrien   (clobber (reg:CC CC_REGNUM))]
979790075Sobrien  "TARGET_ARM && reload_completed"
979890075Sobrien  [(set (match_dup 5) (match_dup 6))
979990075Sobrien   (cond_exec (match_dup 7)
980090075Sobrien	      (set (match_dup 0) (match_dup 4)))]
980190075Sobrien  "
980290075Sobrien  {
980390075Sobrien    enum machine_mode mode = SELECT_CC_MODE (GET_CODE (operands[1]),
980490075Sobrien					     operands[2], operands[3]);
980590075Sobrien    enum rtx_code rc = GET_CODE (operands[1]);
980690075Sobrien
980790075Sobrien    operands[5] = gen_rtx_REG (mode, CC_REGNUM);
980890075Sobrien    operands[6] = gen_rtx_COMPARE (mode, operands[2], operands[3]);
980990075Sobrien    if (mode == CCFPmode || mode == CCFPEmode)
981090075Sobrien      rc = reverse_condition_maybe_unordered (rc);
981190075Sobrien    else
981290075Sobrien      rc = reverse_condition (rc);
981390075Sobrien
981490075Sobrien    operands[7] = gen_rtx_fmt_ee (rc, VOIDmode, operands[5], const0_rtx);
981590075Sobrien  }"
981690075Sobrien)
981790075Sobrien
981890075Sobrien(define_split
981990075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
982090075Sobrien	(if_then_else:SI (match_operator 1 "arm_comparison_operator"
982190075Sobrien			  [(match_operand 2 "" "") (match_operand 3 "" "")])
982290075Sobrien			 (match_operand 4 "" "")
982390075Sobrien			 (match_dup 0)))
982490075Sobrien   (clobber (reg:CC CC_REGNUM))]
982590075Sobrien  "TARGET_ARM && reload_completed"
982690075Sobrien  [(set (match_dup 5) (match_dup 6))
982790075Sobrien   (cond_exec (match_op_dup 1 [(match_dup 5) (const_int 0)])
982890075Sobrien	      (set (match_dup 0) (match_dup 4)))]
982990075Sobrien  "
983090075Sobrien  {
983190075Sobrien    enum machine_mode mode = SELECT_CC_MODE (GET_CODE (operands[1]),
983290075Sobrien					     operands[2], operands[3]);
983390075Sobrien
983490075Sobrien    operands[5] = gen_rtx_REG (mode, CC_REGNUM);
983590075Sobrien    operands[6] = gen_rtx_COMPARE (mode, operands[2], operands[3]);
983690075Sobrien  }"
983790075Sobrien)
983890075Sobrien
983990075Sobrien(define_split
984090075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
984190075Sobrien	(if_then_else:SI (match_operator 1 "arm_comparison_operator"
984290075Sobrien			  [(match_operand 2 "" "") (match_operand 3 "" "")])
984390075Sobrien			 (match_operand 4 "" "")
984490075Sobrien			 (match_operand 5 "" "")))
984590075Sobrien   (clobber (reg:CC CC_REGNUM))]
984690075Sobrien  "TARGET_ARM && reload_completed"
984790075Sobrien  [(set (match_dup 6) (match_dup 7))
984890075Sobrien   (cond_exec (match_op_dup 1 [(match_dup 6) (const_int 0)])
984990075Sobrien	      (set (match_dup 0) (match_dup 4)))
985090075Sobrien   (cond_exec (match_dup 8)
985190075Sobrien	      (set (match_dup 0) (match_dup 5)))]
985290075Sobrien  "
985390075Sobrien  {
985490075Sobrien    enum machine_mode mode = SELECT_CC_MODE (GET_CODE (operands[1]),
985590075Sobrien					     operands[2], operands[3]);
985690075Sobrien    enum rtx_code rc = GET_CODE (operands[1]);
985790075Sobrien
985890075Sobrien    operands[6] = gen_rtx_REG (mode, CC_REGNUM);
985990075Sobrien    operands[7] = gen_rtx_COMPARE (mode, operands[2], operands[3]);
986090075Sobrien    if (mode == CCFPmode || mode == CCFPEmode)
986190075Sobrien      rc = reverse_condition_maybe_unordered (rc);
986290075Sobrien    else
986390075Sobrien      rc = reverse_condition (rc);
986490075Sobrien
986590075Sobrien    operands[8] = gen_rtx_fmt_ee (rc, VOIDmode, operands[6], const0_rtx);
986690075Sobrien  }"
986790075Sobrien)
986890075Sobrien
986990075Sobrien(define_split
987090075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
987190075Sobrien	(if_then_else:SI (match_operator 1 "arm_comparison_operator"
987290075Sobrien			  [(match_operand:SI 2 "s_register_operand" "")
987390075Sobrien			   (match_operand:SI 3 "arm_add_operand" "")])
987490075Sobrien			 (match_operand:SI 4 "arm_rhs_operand" "")
987590075Sobrien			 (not:SI
987690075Sobrien			  (match_operand:SI 5 "s_register_operand" ""))))
987790075Sobrien   (clobber (reg:CC CC_REGNUM))]
987890075Sobrien  "TARGET_ARM && reload_completed"
987990075Sobrien  [(set (match_dup 6) (match_dup 7))
988090075Sobrien   (cond_exec (match_op_dup 1 [(match_dup 6) (const_int 0)])
988190075Sobrien	      (set (match_dup 0) (match_dup 4)))
988290075Sobrien   (cond_exec (match_dup 8)
988390075Sobrien	      (set (match_dup 0) (not:SI (match_dup 5))))]
988490075Sobrien  "
988590075Sobrien  {
988690075Sobrien    enum machine_mode mode = SELECT_CC_MODE (GET_CODE (operands[1]),
988790075Sobrien					     operands[2], operands[3]);
988890075Sobrien    enum rtx_code rc = GET_CODE (operands[1]);
988990075Sobrien
989090075Sobrien    operands[6] = gen_rtx_REG (mode, CC_REGNUM);
9891169689Skan    operands[7] = gen_rtx_COMPARE (mode, operands[2], operands[3]);
989290075Sobrien    if (mode == CCFPmode || mode == CCFPEmode)
989390075Sobrien      rc = reverse_condition_maybe_unordered (rc);
989490075Sobrien    else
989590075Sobrien      rc = reverse_condition (rc);
989690075Sobrien
989790075Sobrien    operands[8] = gen_rtx_fmt_ee (rc, VOIDmode, operands[6], const0_rtx);
989890075Sobrien  }"
989990075Sobrien)
990090075Sobrien
990190075Sobrien(define_insn "*cond_move_not"
990290075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
990390075Sobrien	(if_then_else:SI (match_operator 4 "arm_comparison_operator"
990490075Sobrien			  [(match_operand 3 "cc_register" "") (const_int 0)])
990590075Sobrien			 (match_operand:SI 1 "arm_rhs_operand" "0,?rI")
990690075Sobrien			 (not:SI
990790075Sobrien			  (match_operand:SI 2 "s_register_operand" "r,r"))))]
990890075Sobrien  "TARGET_ARM"
990990075Sobrien  "@
991090075Sobrien   mvn%D4\\t%0, %2
991190075Sobrien   mov%d4\\t%0, %1\;mvn%D4\\t%0, %2"
991290075Sobrien  [(set_attr "conds" "use")
991390075Sobrien   (set_attr "length" "4,8")]
991490075Sobrien)
991590075Sobrien
991690075Sobrien;; The next two patterns occur when an AND operation is followed by a
991790075Sobrien;; scc insn sequence 
991890075Sobrien
991990075Sobrien(define_insn "*sign_extract_onebit"
992090075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
992190075Sobrien	(sign_extract:SI (match_operand:SI 1 "s_register_operand" "r")
992290075Sobrien			 (const_int 1)
9923104752Skan			 (match_operand:SI 2 "const_int_operand" "n")))
9924104752Skan    (clobber (reg:CC CC_REGNUM))]
992590075Sobrien  "TARGET_ARM"
992690075Sobrien  "*
992790075Sobrien    operands[2] = GEN_INT (1 << INTVAL (operands[2]));
992890075Sobrien    output_asm_insn (\"ands\\t%0, %1, %2\", operands);
992990075Sobrien    return \"mvnne\\t%0, #0\";
993090075Sobrien  "
993190075Sobrien  [(set_attr "conds" "clob")
993290075Sobrien   (set_attr "length" "8")]
993390075Sobrien)
993490075Sobrien
993590075Sobrien(define_insn "*not_signextract_onebit"
993690075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
993790075Sobrien	(not:SI
993890075Sobrien	 (sign_extract:SI (match_operand:SI 1 "s_register_operand" "r")
993990075Sobrien			  (const_int 1)
9940104752Skan			  (match_operand:SI 2 "const_int_operand" "n"))))
9941104752Skan   (clobber (reg:CC CC_REGNUM))]
994290075Sobrien  "TARGET_ARM"
994390075Sobrien  "*
994490075Sobrien    operands[2] = GEN_INT (1 << INTVAL (operands[2]));
994590075Sobrien    output_asm_insn (\"tst\\t%1, %2\", operands);
994690075Sobrien    output_asm_insn (\"mvneq\\t%0, #0\", operands);
994790075Sobrien    return \"movne\\t%0, #0\";
994890075Sobrien  "
994990075Sobrien  [(set_attr "conds" "clob")
995090075Sobrien   (set_attr "length" "12")]
995190075Sobrien)
995290075Sobrien
995390075Sobrien;; Push multiple registers to the stack.  Registers are in parallel (use ...)
995490075Sobrien;; expressions.  For simplicity, the first register is also in the unspec
995590075Sobrien;; part.
995690075Sobrien(define_insn "*push_multi"
995790075Sobrien  [(match_parallel 2 "multi_register_push"
995890075Sobrien    [(set (match_operand:BLK 0 "memory_operand" "=m")
995990075Sobrien	  (unspec:BLK [(match_operand:SI 1 "s_register_operand" "r")]
996090075Sobrien		      UNSPEC_PUSH_MULT))])]
996190075Sobrien  "TARGET_ARM"
996290075Sobrien  "*
996390075Sobrien  {
996490075Sobrien    int num_saves = XVECLEN (operands[2], 0);
996590075Sobrien     
996690075Sobrien    /* For the StrongARM at least it is faster to
996790075Sobrien       use STR to store only a single register.  */
996890075Sobrien    if (num_saves == 1)
996990075Sobrien      output_asm_insn (\"str\\t%1, [%m0, #-4]!\", operands);
997090075Sobrien    else
997190075Sobrien      {
997290075Sobrien	int i;
997390075Sobrien	char pattern[100];
997490075Sobrien
997590075Sobrien	strcpy (pattern, \"stmfd\\t%m0!, {%1\");
997690075Sobrien
997790075Sobrien	for (i = 1; i < num_saves; i++)
997890075Sobrien	  {
997990075Sobrien	    strcat (pattern, \", %|\");
998090075Sobrien	    strcat (pattern,
998190075Sobrien		    reg_names[REGNO (XEXP (XVECEXP (operands[2], 0, i), 0))]);
998290075Sobrien	  }
998390075Sobrien
998490075Sobrien	strcat (pattern, \"}\");
998590075Sobrien	output_asm_insn (pattern, operands);
998690075Sobrien      }
998790075Sobrien
998890075Sobrien    return \"\";
998990075Sobrien  }"
999090075Sobrien  [(set_attr "type" "store4")]
999190075Sobrien)
999290075Sobrien
9993117395Skan(define_insn "stack_tie"
9994117395Skan  [(set (mem:BLK (scratch))
9995117395Skan	(unspec:BLK [(match_operand:SI 0 "s_register_operand" "r")
9996117395Skan		     (match_operand:SI 1 "s_register_operand" "r")]
9997117395Skan		    UNSPEC_PRLG_STK))]
9998117395Skan  ""
9999117395Skan  ""
10000117395Skan  [(set_attr "length" "0")]
10001117395Skan)
10002117395Skan
1000390075Sobrien;; Similarly for the floating point registers
1000490075Sobrien(define_insn "*push_fp_multi"
1000590075Sobrien  [(match_parallel 2 "multi_register_push"
1000690075Sobrien    [(set (match_operand:BLK 0 "memory_operand" "=m")
1000790075Sobrien	  (unspec:BLK [(match_operand:XF 1 "f_register_operand" "f")]
1000890075Sobrien		      UNSPEC_PUSH_MULT))])]
10009169689Skan  "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_FPA"
1001090075Sobrien  "*
1001190075Sobrien  {
1001290075Sobrien    char pattern[100];
1001390075Sobrien
1001490075Sobrien    sprintf (pattern, \"sfmfd\\t%%1, %d, [%%m0]!\", XVECLEN (operands[2], 0));
1001590075Sobrien    output_asm_insn (pattern, operands);
1001690075Sobrien    return \"\";
1001790075Sobrien  }"
1001890075Sobrien  [(set_attr "type" "f_store")]
1001990075Sobrien)
1002090075Sobrien
1002190075Sobrien;; Special patterns for dealing with the constant pool
1002290075Sobrien
1002390075Sobrien(define_insn "align_4"
1002490075Sobrien  [(unspec_volatile [(const_int 0)] VUNSPEC_ALIGN)]
1002590075Sobrien  "TARGET_EITHER"
1002690075Sobrien  "*
1002790075Sobrien  assemble_align (32);
1002890075Sobrien  return \"\";
1002990075Sobrien  "
1003090075Sobrien)
1003190075Sobrien
10032132718Skan(define_insn "align_8"
10033132718Skan  [(unspec_volatile [(const_int 0)] VUNSPEC_ALIGN8)]
10034169689Skan  "TARGET_EITHER"
10035132718Skan  "*
10036132718Skan  assemble_align (64);
10037132718Skan  return \"\";
10038132718Skan  "
10039132718Skan)
10040132718Skan
1004190075Sobrien(define_insn "consttable_end"
1004290075Sobrien  [(unspec_volatile [(const_int 0)] VUNSPEC_POOL_END)]
1004390075Sobrien  "TARGET_EITHER"
1004490075Sobrien  "*
1004590075Sobrien  making_const_table = FALSE;
1004690075Sobrien  return \"\";
1004790075Sobrien  "
1004890075Sobrien)
1004990075Sobrien
1005090075Sobrien(define_insn "consttable_1"
1005190075Sobrien  [(unspec_volatile [(match_operand 0 "" "")] VUNSPEC_POOL_1)]
1005290075Sobrien  "TARGET_THUMB"
1005390075Sobrien  "*
1005490075Sobrien  making_const_table = TRUE;
1005590075Sobrien  assemble_integer (operands[0], 1, BITS_PER_WORD, 1);
1005690075Sobrien  assemble_zeros (3);
1005790075Sobrien  return \"\";
1005890075Sobrien  "
1005990075Sobrien  [(set_attr "length" "4")]
1006090075Sobrien)
1006190075Sobrien
1006290075Sobrien(define_insn "consttable_2"
1006390075Sobrien  [(unspec_volatile [(match_operand 0 "" "")] VUNSPEC_POOL_2)]
1006490075Sobrien  "TARGET_THUMB"
1006590075Sobrien  "*
1006690075Sobrien  making_const_table = TRUE;
1006790075Sobrien  assemble_integer (operands[0], 2, BITS_PER_WORD, 1);
1006890075Sobrien  assemble_zeros (2);
1006990075Sobrien  return \"\";
1007090075Sobrien  "
1007190075Sobrien  [(set_attr "length" "4")]
1007290075Sobrien)
1007390075Sobrien
1007490075Sobrien(define_insn "consttable_4"
1007590075Sobrien  [(unspec_volatile [(match_operand 0 "" "")] VUNSPEC_POOL_4)]
1007690075Sobrien  "TARGET_EITHER"
1007790075Sobrien  "*
1007890075Sobrien  {
1007990075Sobrien    making_const_table = TRUE;
1008090075Sobrien    switch (GET_MODE_CLASS (GET_MODE (operands[0])))
1008190075Sobrien      {
1008290075Sobrien      case MODE_FLOAT:
1008390075Sobrien      {
10084117395Skan        REAL_VALUE_TYPE r;
10085117395Skan        REAL_VALUE_FROM_CONST_DOUBLE (r, operands[0]);
10086117395Skan        assemble_real (r, GET_MODE (operands[0]), BITS_PER_WORD);
1008790075Sobrien        break;
1008890075Sobrien      }
1008990075Sobrien      default:
1009090075Sobrien        assemble_integer (operands[0], 4, BITS_PER_WORD, 1);
1009190075Sobrien        break;
1009290075Sobrien      }
1009390075Sobrien    return \"\";
1009490075Sobrien  }"
1009590075Sobrien  [(set_attr "length" "4")]
1009690075Sobrien)
1009790075Sobrien
1009890075Sobrien(define_insn "consttable_8"
1009990075Sobrien  [(unspec_volatile [(match_operand 0 "" "")] VUNSPEC_POOL_8)]
1010090075Sobrien  "TARGET_EITHER"
1010190075Sobrien  "*
1010290075Sobrien  {
1010390075Sobrien    making_const_table = TRUE;
1010490075Sobrien    switch (GET_MODE_CLASS (GET_MODE (operands[0])))
1010590075Sobrien      {
1010690075Sobrien       case MODE_FLOAT:
1010790075Sobrien        {
10108117395Skan          REAL_VALUE_TYPE r;
10109117395Skan          REAL_VALUE_FROM_CONST_DOUBLE (r, operands[0]);
10110117395Skan          assemble_real (r, GET_MODE (operands[0]), BITS_PER_WORD);
1011190075Sobrien          break;
1011290075Sobrien        }
1011390075Sobrien      default:
1011490075Sobrien        assemble_integer (operands[0], 8, BITS_PER_WORD, 1);
1011590075Sobrien        break;
1011690075Sobrien      }
1011790075Sobrien    return \"\";
1011890075Sobrien  }"
1011990075Sobrien  [(set_attr "length" "8")]
1012090075Sobrien)
1012190075Sobrien
1012290075Sobrien;; Miscellaneous Thumb patterns
1012390075Sobrien
1012496263Sobrien(define_expand "tablejump"
10125132718Skan  [(parallel [(set (pc) (match_operand:SI 0 "register_operand" ""))
1012696263Sobrien	      (use (label_ref (match_operand 1 "" "")))])]
1012796263Sobrien  "TARGET_THUMB"
1012896263Sobrien  "
1012996263Sobrien  if (flag_pic)
1013096263Sobrien    {
1013196263Sobrien      /* Hopefully, CSE will eliminate this copy.  */
1013296263Sobrien      rtx reg1 = copy_addr_to_reg (gen_rtx_LABEL_REF (Pmode, operands[1]));
1013396263Sobrien      rtx reg2 = gen_reg_rtx (SImode);
1013496263Sobrien
1013596263Sobrien      emit_insn (gen_addsi3 (reg2, operands[0], reg1));
1013696263Sobrien      operands[0] = reg2;
1013796263Sobrien    }
1013896263Sobrien  "
1013996263Sobrien)
1014096263Sobrien
10141169689Skan;; NB never uses BX.
1014296263Sobrien(define_insn "*thumb_tablejump"
1014390075Sobrien  [(set (pc) (match_operand:SI 0 "register_operand" "l*r"))
1014490075Sobrien   (use (label_ref (match_operand 1 "" "")))]
1014590075Sobrien  "TARGET_THUMB"
1014696263Sobrien  "mov\\t%|pc, %0"
1014790075Sobrien  [(set_attr "length" "2")]
1014890075Sobrien)
1014990075Sobrien
1015090075Sobrien;; V5 Instructions,
1015190075Sobrien
10152132718Skan(define_insn "clzsi2"
10153132718Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
10154132718Skan	(clz:SI (match_operand:SI 1 "s_register_operand" "r")))]
1015590075Sobrien  "TARGET_ARM && arm_arch5"
10156132718Skan  "clz%?\\t%0, %1"
10157132718Skan  [(set_attr "predicable" "yes")])
1015890075Sobrien
1015990075Sobrien(define_expand "ffssi2"
1016090075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
1016190075Sobrien	(ffs:SI (match_operand:SI 1 "s_register_operand" "")))]
1016290075Sobrien  "TARGET_ARM && arm_arch5"
1016390075Sobrien  "
1016490075Sobrien  {
1016590075Sobrien    rtx t1, t2, t3;
1016690075Sobrien
1016790075Sobrien    t1 = gen_reg_rtx (SImode);
1016890075Sobrien    t2 = gen_reg_rtx (SImode);
1016990075Sobrien    t3 = gen_reg_rtx (SImode);
1017090075Sobrien
1017190075Sobrien    emit_insn (gen_negsi2 (t1, operands[1]));
1017290075Sobrien    emit_insn (gen_andsi3 (t2, operands[1], t1));
10173132718Skan    emit_insn (gen_clzsi2 (t3, t2));
1017490075Sobrien    emit_insn (gen_subsi3 (operands[0], GEN_INT (32), t3));
1017590075Sobrien    DONE;
1017690075Sobrien  }"
1017790075Sobrien)
1017890075Sobrien
10179132718Skan(define_expand "ctzsi2"
10180132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
10181132718Skan	(ctz:SI (match_operand:SI 1 "s_register_operand" "")))]
10182132718Skan  "TARGET_ARM && arm_arch5"
10183132718Skan  "
10184132718Skan  {
10185132718Skan    rtx t1, t2, t3;
10186132718Skan
10187132718Skan    t1 = gen_reg_rtx (SImode);
10188132718Skan    t2 = gen_reg_rtx (SImode);
10189132718Skan    t3 = gen_reg_rtx (SImode);
10190132718Skan
10191132718Skan    emit_insn (gen_negsi2 (t1, operands[1]));
10192132718Skan    emit_insn (gen_andsi3 (t2, operands[1], t1));
10193132718Skan    emit_insn (gen_clzsi2 (t3, t2));
10194132718Skan    emit_insn (gen_subsi3 (operands[0], GEN_INT (31), t3));
10195132718Skan    DONE;
10196132718Skan  }"
10197132718Skan)
10198132718Skan
1019990075Sobrien;; V5E instructions.
1020090075Sobrien
1020190075Sobrien(define_insn "prefetch"
1020290075Sobrien  [(prefetch (match_operand:SI 0 "address_operand" "p")
1020390075Sobrien	     (match_operand:SI 1 "" "")
1020490075Sobrien	     (match_operand:SI 2 "" ""))]
1020590075Sobrien  "TARGET_ARM && arm_arch5e"
1020690075Sobrien  "pld\\t%a0")
1020790075Sobrien
1020890075Sobrien;; General predication pattern
1020990075Sobrien
1021090075Sobrien(define_cond_exec
1021190075Sobrien  [(match_operator 0 "arm_comparison_operator"
1021290075Sobrien    [(match_operand 1 "cc_register" "")
1021390075Sobrien     (const_int 0)])]
1021490075Sobrien  "TARGET_ARM"
1021590075Sobrien  ""
1021690075Sobrien)
1021790075Sobrien
1021890075Sobrien(define_insn "prologue_use"
1021990075Sobrien  [(unspec:SI [(match_operand:SI 0 "register_operand" "")] UNSPEC_PROLOGUE_USE)]
1022090075Sobrien  ""
1022190075Sobrien  "%@ %0 needed for prologue"
1022290075Sobrien)
10223132718Skan
10224169689Skan
10225169689Skan;; Patterns for exception handling
10226169689Skan
10227169689Skan(define_expand "eh_return"
10228169689Skan  [(use (match_operand 0 "general_operand" ""))]
10229169689Skan  "TARGET_EITHER"
10230169689Skan  "
10231169689Skan  {
10232169689Skan    if (TARGET_ARM)
10233169689Skan      emit_insn (gen_arm_eh_return (operands[0]));
10234169689Skan    else
10235169689Skan      emit_insn (gen_thumb_eh_return (operands[0]));
10236169689Skan    DONE;
10237169689Skan  }"
10238169689Skan)
10239169689Skan				   
10240169689Skan;; We can't expand this before we know where the link register is stored.
10241169689Skan(define_insn_and_split "arm_eh_return"
10242169689Skan  [(unspec_volatile [(match_operand:SI 0 "s_register_operand" "r")]
10243169689Skan		    VUNSPEC_EH_RETURN)
10244169689Skan   (clobber (match_scratch:SI 1 "=&r"))]
10245169689Skan  "TARGET_ARM"
10246169689Skan  "#"
10247169689Skan  "&& reload_completed"
10248169689Skan  [(const_int 0)]
10249169689Skan  "
10250169689Skan  {
10251169689Skan    arm_set_return_address (operands[0], operands[1]);
10252169689Skan    DONE;
10253169689Skan  }"
10254169689Skan)
10255169689Skan
10256169689Skan(define_insn_and_split "thumb_eh_return"
10257169689Skan  [(unspec_volatile [(match_operand:SI 0 "s_register_operand" "l")]
10258169689Skan		    VUNSPEC_EH_RETURN)
10259169689Skan   (clobber (match_scratch:SI 1 "=&l"))]
10260169689Skan  "TARGET_THUMB"
10261169689Skan  "#"
10262169689Skan  "&& reload_completed"
10263169689Skan  [(const_int 0)]
10264169689Skan  "
10265169689Skan  {
10266169689Skan    thumb_set_return_address (operands[0], operands[1]);
10267169689Skan    DONE;
10268169689Skan  }"
10269169689Skan)
10270169689Skan
10271169689Skan
10272169689Skan;; TLS support
10273169689Skan
10274169689Skan(define_insn "load_tp_hard"
10275169689Skan  [(set (match_operand:SI 0 "register_operand" "=r")
10276169689Skan	(unspec:SI [(const_int 0)] UNSPEC_TLS))]
10277169689Skan  "TARGET_HARD_TP"
10278169689Skan  "mrc%?\\tp15, 0, %0, c13, c0, 3\\t@ load_tp_hard"
10279169689Skan  [(set_attr "predicable" "yes")]
10280169689Skan)
10281169689Skan
10282169689Skan;; Doesn't clobber R1-R3.  Must use r0 for the first operand.
10283169689Skan(define_insn "load_tp_soft"
10284169689Skan  [(set (reg:SI 0) (unspec:SI [(const_int 0)] UNSPEC_TLS))
10285169689Skan   (clobber (reg:SI LR_REGNUM))
10286169689Skan   (clobber (reg:SI IP_REGNUM))
10287169689Skan   (clobber (reg:CC CC_REGNUM))]
10288169689Skan  "TARGET_SOFT_TP"
10289169689Skan  "bl\\t__aeabi_read_tp\\t@ load_tp_soft"
10290169689Skan  [(set_attr "conds" "clob")]
10291169689Skan)
10292169689Skan
10293132718Skan;; Load the FPA co-processor patterns
10294132718Skan(include "fpa.md")
10295132718Skan;; Load the Maverick co-processor patterns
10296132718Skan(include "cirrus.md")
10297132718Skan;; Load the Intel Wireless Multimedia Extension patterns
10298132718Skan(include "iwmmxt.md")
10299169689Skan;; Load the VFP co-processor patterns
10300169689Skan(include "vfp.md")
10301169689Skan
10302