arm.md revision 132718
190075Sobrien;;- Machine description for ARM for GNU compiler
290075Sobrien;;  Copyright 1991, 1993, 1994, 1995, 1996, 1996, 1997, 1998, 1999, 2000,
3132718Skan;;  2001, 2002, 2003 2004  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
2290075Sobrien;; the Free Software Foundation, 59 Temple Place - Suite 330,
2390075Sobrien;; Boston, MA 02111-1307, 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
3390075Sobrien  [(IP_REGNUM	    12)		; Scratch register
3490075Sobrien   (SP_REGNUM	    13)		; Stack pointer
3590075Sobrien   (LR_REGNUM       14)		; Return address register
3690075Sobrien   (PC_REGNUM	    15)		; Program counter
3790075Sobrien   (CC_REGNUM       24)		; Condition code pseudo register
3890075Sobrien   (LAST_ARM_REGNUM 15)
3990075Sobrien  ]
4090075Sobrien)
41132718Skan;; 3rd operand to select_dominance_cc_mode
42132718Skan(define_constants
43132718Skan  [(DOM_CC_X_AND_Y  0)
44132718Skan   (DOM_CC_NX_OR_Y  1)
45132718Skan   (DOM_CC_X_OR_Y   2)
46132718Skan  ]
47132718Skan)
4890075Sobrien
4990075Sobrien;; UNSPEC Usage:
5090075Sobrien;; Note: sin and cos are no-longer used.
5190075Sobrien
5290075Sobrien(define_constants
5390075Sobrien  [(UNSPEC_SIN       0)	; `sin' operation (MODE_FLOAT):
5490075Sobrien			;   operand 0 is the result,
5590075Sobrien			;   operand 1 the parameter.
5690075Sobrien   (UNPSEC_COS	     1)	; `cos' operation (MODE_FLOAT):
5790075Sobrien			;   operand 0 is the result,
5890075Sobrien			;   operand 1 the parameter.
5990075Sobrien   (UNSPEC_PUSH_MULT 2)	; `push multiple' operation:
6090075Sobrien			;   operand 0 is the first register,
6190075Sobrien			;   subsequent registers are in parallel (use ...)
6290075Sobrien			;   expressions.
6390075Sobrien   (UNSPEC_PIC_SYM   3) ; A symbol that has been treated properly for pic
6490075Sobrien			;   usage, that is, we will add the pic_register
6590075Sobrien			;   value to it before trying to dereference it.
66117395Skan   (UNSPEC_PIC_BASE  4)	; Adding the PC value to the offset to the
67117395Skan			;   GLOBAL_OFFSET_TABLE.  The operation is fully
68117395Skan			;   described by the RTL but must be wrapped to
69117395Skan			;   prevent combine from trying to rip it apart.
70117395Skan   (UNSPEC_PRLG_STK  5) ; A special barrier that prevents frame accesses 
7190075Sobrien			;   being scheduled before the stack adjustment insn.
7290075Sobrien   (UNSPEC_PROLOGUE_USE 6) ; As USE insns are not meaningful after reload,
7390075Sobrien   			; this unspec is used to prevent the deletion of
7490075Sobrien   			; instructions setting registers for EH handling
7590075Sobrien   			; and stack frame generation.  Operand 0 is the
7690075Sobrien   			; register to "use".
77117395Skan   (UNSPEC_CHECK_ARCH 7); Set CCs to indicate 26-bit or 32-bit mode.
78132718Skan   (UNSPEC_WSHUFH    8) ; Used by the intrinsic form of the iWMMXt WSHUFH instruction.
79132718Skan   (UNSPEC_WACC      9) ; Used by the intrinsic form of the iWMMXt WACC instruction.
80132718Skan   (UNSPEC_TMOVMSK  10) ; Used by the intrinsic form of the iWMMXt TMOVMSK instruction.
81132718Skan   (UNSPEC_WSAD     11) ; Used by the intrinsic form of the iWMMXt WSAD instruction.
82132718Skan   (UNSPEC_WSADZ    12) ; Used by the intrinsic form of the iWMMXt WSADZ instruction.
83132718Skan   (UNSPEC_WMACS    13) ; Used by the intrinsic form of the iWMMXt WMACS instruction.
84132718Skan   (UNSPEC_WMACU    14) ; Used by the intrinsic form of the iWMMXt WMACU instruction.
85132718Skan   (UNSPEC_WMACSZ   15) ; Used by the intrinsic form of the iWMMXt WMACSZ instruction.
86132718Skan   (UNSPEC_WMACUZ   16) ; Used by the intrinsic form of the iWMMXt WMACUZ instruction.
87132718Skan   (UNSPEC_CLRDI    17) ; Used by the intrinsic form of the iWMMXt CLRDI instruction.
88132718Skan   (UNSPEC_WMADDS   18) ; Used by the intrinsic form of the iWMMXt WMADDS instruction.
89132718Skan   (UNSPEC_WMADDU   19) ; Used by the intrinsic form of the iWMMXt WMADDU instruction.
9090075Sobrien  ]
9190075Sobrien)
9290075Sobrien
9390075Sobrien;; UNSPEC_VOLATILE Usage:
9490075Sobrien
9590075Sobrien(define_constants
9690075Sobrien  [(VUNSPEC_BLOCKAGE 0) ; `blockage' insn to prevent scheduling across an
9790075Sobrien			;   insn in the code.
9890075Sobrien   (VUNSPEC_EPILOGUE 1) ; `epilogue' insn, used to represent any part of the
9990075Sobrien			;   instruction epilogue sequence that isn't expanded
10090075Sobrien			;   into normal RTL.  Used for both normal and sibcall
10190075Sobrien			;   epilogues.
10290075Sobrien   (VUNSPEC_ALIGN    2) ; `align' insn.  Used at the head of a minipool table 
10390075Sobrien			;   for inlined constants.
10490075Sobrien   (VUNSPEC_POOL_END 3) ; `end-of-table'.  Used to mark the end of a minipool
10590075Sobrien			;   table.
10690075Sobrien   (VUNSPEC_POOL_1   4) ; `pool-entry(1)'.  An entry in the constant pool for
10790075Sobrien			;   an 8-bit object.
10890075Sobrien   (VUNSPEC_POOL_2   5) ; `pool-entry(2)'.  An entry in the constant pool for
10990075Sobrien			;   a 16-bit object.
11090075Sobrien   (VUNSPEC_POOL_4   6) ; `pool-entry(4)'.  An entry in the constant pool for
11190075Sobrien			;   a 32-bit object.
11290075Sobrien   (VUNSPEC_POOL_8   7) ; `pool-entry(8)'.  An entry in the constant pool for
11390075Sobrien			;   a 64-bit object.
114132718Skan   (VUNSPEC_TMRC     8) ; Used by the iWMMXt TMRC instruction.
115132718Skan   (VUNSPEC_TMCR     9) ; Used by the iWMMXt TMCR instruction.
116132718Skan   (VUNSPEC_ALIGN8   10) ; 8-byte alignment version of VUNSPEC_ALIGN
117132718Skan   (VUNSPEC_WCMP_EQ  11) ; Used by the iWMMXt WCMPEQ instructions
118132718Skan   (VUNSPEC_WCMP_GTU 12) ; Used by the iWMMXt WCMPGTU instructions
119132718Skan   (VUNSPEC_WCMP_GT  13) ; Used by the iwMMXT WCMPGT instructions
12090075Sobrien  ]
12190075Sobrien)
12290075Sobrien
12390075Sobrien;;---------------------------------------------------------------------------
12490075Sobrien;; Attributes
12590075Sobrien
12690075Sobrien; IS_THUMB is set to 'yes' when we are generating Thumb code, and 'no' when
12790075Sobrien; generating ARM code.  This is used to control the length of some insn
12890075Sobrien; patterns that share the same RTL in both ARM and Thumb code.
12990075Sobrien(define_attr "is_thumb" "no,yes" (const (symbol_ref "thumb_code")))
13090075Sobrien
13190075Sobrien; PROG_MODE attribute is used to determine whether condition codes are
13290075Sobrien; clobbered by a call insn: they are if in prog32 mode.  This is controlled
13390075Sobrien; by the -mapcs-{32,26} flag, and possibly the -mcpu=... option.
13490075Sobrien(define_attr "prog_mode" "prog26,prog32" (const (symbol_ref "arm_prog_mode")))
13590075Sobrien
13690075Sobrien; IS_STRONGARM is set to 'yes' when compiling for StrongARM, it affects
13790075Sobrien; scheduling decisions for the load unit and the multiplier.
13890075Sobrien(define_attr "is_strongarm" "no,yes" (const (symbol_ref "arm_is_strong")))
13990075Sobrien
14090075Sobrien;; Operand number of an input operand that is shifted.  Zero if the
14190075Sobrien;; given instruction does not shift one of its input operands.
142132718Skan(define_attr "is_xscale" "no,yes" (const (symbol_ref "arm_tune_xscale")))
14390075Sobrien(define_attr "shift" "" (const_int 0))
14490075Sobrien
14590075Sobrien; Floating Point Unit.  If we only have floating point emulation, then there
14690075Sobrien; is no point in scheduling the floating point insns.  (Well, for best
14790075Sobrien; performance we should try and group them together).
148132718Skan(define_attr "fpu" "softfpa,fpa,fpe2,fpe3,maverick"
149132718Skan  (const (symbol_ref "arm_fpu_attr")))
15090075Sobrien
15190075Sobrien; LENGTH of an instruction (in bytes)
15290075Sobrien(define_attr "length" "" (const_int 4))
15390075Sobrien
15490075Sobrien; POOL_RANGE is how far away from a constant pool entry that this insn
15590075Sobrien; can be placed.  If the distance is zero, then this insn will never
15690075Sobrien; reference the pool.
15790075Sobrien; NEG_POOL_RANGE is nonzero for insns that can reference a constant pool entry
15890075Sobrien; before its address.
15990075Sobrien(define_attr "pool_range" "" (const_int 0))
16090075Sobrien(define_attr "neg_pool_range" "" (const_int 0))
16190075Sobrien
16290075Sobrien; An assembler sequence may clobber the condition codes without us knowing.
16396263Sobrien; If such an insn references the pool, then we have no way of knowing how,
16496263Sobrien; so use the most conservative value for pool_range.
16590075Sobrien(define_asm_attributes
16696263Sobrien [(set_attr "conds" "clob")
16796263Sobrien  (set_attr "length" "4")
16896263Sobrien  (set_attr "pool_range" "250")])
16990075Sobrien
17090075Sobrien; TYPE attribute is used to detect floating point instructions which, if
17190075Sobrien; running on a co-processor can run in parallel with other, basic instructions
17290075Sobrien; If write-buffer scheduling is enabled then it can also be used in the
17390075Sobrien; scheduling of writes.
17490075Sobrien
17590075Sobrien; Classification of each insn
17690075Sobrien; normal	any data instruction that doesn't hit memory or fp regs
17790075Sobrien; mult		a multiply instruction
17890075Sobrien; block		blockage insn, this blocks all functional units
17990075Sobrien; float		a floating point arithmetic operation (subject to expansion)
18090075Sobrien; fdivd		DFmode floating point division
18190075Sobrien; fdivs		SFmode floating point division
18290075Sobrien; fmul		Floating point multiply
18390075Sobrien; ffmul		Fast floating point multiply
18490075Sobrien; farith	Floating point arithmetic (4 cycle)
18590075Sobrien; ffarith	Fast floating point arithmetic (2 cycle)
18690075Sobrien; float_em	a floating point arithmetic operation that is normally emulated
18790075Sobrien;		even on a machine with an fpa.
18890075Sobrien; f_load	a floating point load from memory
18990075Sobrien; f_store	a floating point store to memory
19090075Sobrien; f_mem_r	a transfer of a floating point register to a real reg via mem
19190075Sobrien; r_mem_f	the reverse of f_mem_r
19290075Sobrien; f_2_r		fast transfer float to arm (no memory needed)
19390075Sobrien; r_2_f		fast transfer arm to float
19490075Sobrien; call		a subroutine call
19590075Sobrien; load		any load from memory
19690075Sobrien; store1	store 1 word to memory from arm registers
19790075Sobrien; store2	store 2 words
19890075Sobrien; store3	store 3 words
19990075Sobrien; store4	store 4 words
200132718Skan;  Additions for Cirrus Maverick co-processor:
201132718Skan; mav_farith	Floating point arithmetic (4 cycle)
202132718Skan; mav_dmult	Double multiplies (7 cycle)
20390075Sobrien;
20490075Sobrien(define_attr "type"
205132718Skan	"normal,mult,block,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith,float_em,f_load,f_store,f_mem_r,r_mem_f,f_2_r,r_2_f,call,load,store1,store2,store3,store4,mav_farith,mav_dmult" 
20690075Sobrien	(const_string "normal"))
20790075Sobrien
20890075Sobrien; Load scheduling, set from the arm_ld_sched variable
209117395Skan; initialized by arm_override_options() 
21090075Sobrien(define_attr "ldsched" "no,yes" (const (symbol_ref "arm_ld_sched")))
21190075Sobrien
21290075Sobrien; condition codes: this one is used by final_prescan_insn to speed up
21390075Sobrien; conditionalizing instructions.  It saves having to scan the rtl to see if
21490075Sobrien; it uses or alters the condition codes.
21590075Sobrien; 
21690075Sobrien; USE means that the condition codes are used by the insn in the process of
21790075Sobrien;   outputting code, this means (at present) that we can't use the insn in
21890075Sobrien;   inlined branches
21990075Sobrien;
22090075Sobrien; SET means that the purpose of the insn is to set the condition codes in a
22190075Sobrien;   well defined manner.
22290075Sobrien;
22390075Sobrien; CLOB means that the condition codes are altered in an undefined manner, if
22490075Sobrien;   they are altered at all
22590075Sobrien;
22690075Sobrien; JUMP_CLOB is used when the condition cannot be represented by a single
22790075Sobrien;   instruction (UNEQ and LTGT).  These cannot be predicated.
22890075Sobrien;
22990075Sobrien; NOCOND means that the condition codes are neither altered nor affect the
23090075Sobrien;   output of this insn
23190075Sobrien
23290075Sobrien(define_attr "conds" "use,set,clob,jump_clob,nocond"
23390075Sobrien	(if_then_else (eq_attr "type" "call")
23490075Sobrien	 (if_then_else (eq_attr "prog_mode" "prog32")
23590075Sobrien	  (const_string "clob") (const_string "nocond"))
23690075Sobrien	 (const_string "nocond")))
23790075Sobrien
23890075Sobrien; Predicable means that the insn can be conditionally executed based on
23990075Sobrien; an automatically added predicate (additional patterns are generated by 
24090075Sobrien; gen...).  We default to 'no' because no Thumb patterns match this rule
24190075Sobrien; and not all ARM patterns do.
24290075Sobrien(define_attr "predicable" "no,yes" (const_string "no"))
24390075Sobrien
24490075Sobrien; Only model the write buffer for ARM6 and ARM7.  Earlier processors don't
24590075Sobrien; have one.  Later ones, such as StrongARM, have write-back caches, so don't
246132718Skan; suffer blockages enough to warrant modelling this (and it can adversely
24790075Sobrien; affect the schedule).
24890075Sobrien(define_attr "model_wbuf" "no,yes" (const (symbol_ref "arm_is_6_or_7")))
24990075Sobrien
25090075Sobrien; WRITE_CONFLICT implies that a read following an unrelated write is likely
25190075Sobrien; to stall the processor.  Used with model_wbuf above.
25290075Sobrien(define_attr "write_conflict" "no,yes"
25390075Sobrien  (if_then_else (eq_attr "type"
25490075Sobrien		 "block,float_em,f_load,f_store,f_mem_r,r_mem_f,call,load")
25590075Sobrien		(const_string "yes")
25690075Sobrien		(const_string "no")))
25790075Sobrien
25890075Sobrien; Classify the insns into those that take one cycle and those that take more
25990075Sobrien; than one on the main cpu execution unit.
26090075Sobrien(define_attr "core_cycles" "single,multi"
26190075Sobrien  (if_then_else (eq_attr "type"
26290075Sobrien		 "normal,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith")
26390075Sobrien		(const_string "single")
26490075Sobrien	        (const_string "multi")))
26590075Sobrien
26690075Sobrien;; FAR_JUMP is "yes" if a BL instruction is used to generate a branch to a
26790075Sobrien;; distant label.  Only applicable to Thumb code.
26890075Sobrien(define_attr "far_jump" "yes,no" (const_string "no"))
26990075Sobrien
270132718Skan(define_automaton "arm")
27190075Sobrien
27290075Sobrien;; Write buffer
273132718Skan;
27490075Sobrien; Strictly, we should model a 4-deep write buffer for ARM7xx based chips
27590075Sobrien;
27690075Sobrien; The write buffer on some of the arm6 processors is hard to model exactly.
27790075Sobrien; There is room in the buffer for up to two addresses and up to eight words
27890075Sobrien; of memory, but the two needn't be split evenly.  When writing the two
27990075Sobrien; addresses are fully pipelined.  However, a read from memory that is not
28090075Sobrien; currently in the cache will block until the writes have completed.
28190075Sobrien; It is normally the case that FCLK and MCLK will be in the ratio 2:1, so
28290075Sobrien; writes will take 2 FCLK cycles per word, if FCLK and MCLK are asynchronous
28390075Sobrien; (they aren't allowed to be at present) then there is a startup cost of 1MCLK
28490075Sobrien; cycle to add as well.
285132718Skan(define_cpu_unit "write_buf" "arm")
28690075Sobrien
28790075Sobrien;; Write blockage unit
288132718Skan;
28990075Sobrien; The write_blockage unit models (partially), the fact that reads will stall
29090075Sobrien; until the write buffer empties.
29190075Sobrien; The f_mem_r and r_mem_f could also block, but they are to the stack,
29290075Sobrien; so we don't model them here
293132718Skan(define_cpu_unit "write_blockage" "arm")
29490075Sobrien
295132718Skan;; Core
296132718Skan;
297132718Skan(define_cpu_unit "core" "arm")
29890075Sobrien
299132718Skan(define_insn_reservation "r_mem_f_wbuf" 5
300132718Skan  (and (eq_attr "model_wbuf" "yes")
301132718Skan       (eq_attr "type" "r_mem_f"))
302132718Skan  "core+write_buf*3")
30390075Sobrien
304132718Skan(define_insn_reservation "store1_wbuf" 5
305132718Skan  (and (eq_attr "model_wbuf" "yes")
306132718Skan       (eq_attr "type" "store1"))
307132718Skan  "core+write_buf*3+write_blockage*5")
30890075Sobrien
309132718Skan(define_insn_reservation "store2_wbuf" 7
310132718Skan  (and (eq_attr "model_wbuf" "yes")
311132718Skan       (eq_attr "type" "store2"))
312132718Skan  "core+write_buf*4+write_blockage*7")
31390075Sobrien
314132718Skan(define_insn_reservation "store3_wbuf" 9
315132718Skan  (and (eq_attr "model_wbuf" "yes")
316132718Skan       (eq_attr "type" "store3"))
317132718Skan  "core+write_buf*5+write_blockage*9")
31890075Sobrien
319132718Skan(define_insn_reservation "store4_wbuf" 11
320132718Skan  (and (eq_attr "model_wbuf" "yes")
321132718Skan       (eq_attr "type" "store4"))
322132718Skan  "core+write_buf*6+write_blockage*11")
32390075Sobrien
324132718Skan(define_insn_reservation "store2" 3
325132718Skan  (and (eq_attr "model_wbuf" "no")
326132718Skan       (eq_attr "type" "store2"))
327132718Skan  "core*3")
32890075Sobrien
329132718Skan(define_insn_reservation "store3" 4
330132718Skan  (and (eq_attr "model_wbuf" "no")
331132718Skan       (eq_attr "type" "store3"))
332132718Skan  "core*4")
33390075Sobrien
334132718Skan(define_insn_reservation "store4" 5
335132718Skan  (and (eq_attr "model_wbuf" "no")
336132718Skan       (eq_attr "type" "store4"))
337132718Skan  "core*5")
33890075Sobrien
339132718Skan(define_insn_reservation "store1_ldsched" 1
340132718Skan  (and (eq_attr "ldsched" "yes") (eq_attr "type" "store1"))
341132718Skan  "core")
34290075Sobrien
343132718Skan(define_insn_reservation "load_ldsched_xscale" 3
344132718Skan  (and (and (eq_attr "ldsched" "yes") (eq_attr "type" "load"))
345132718Skan       (eq_attr "is_xscale" "yes"))
346132718Skan  "core")
34790075Sobrien
348132718Skan(define_insn_reservation "load_ldsched" 2
349132718Skan  (and (and (eq_attr "ldsched" "yes") (eq_attr "type" "load"))
350132718Skan       (eq_attr "is_xscale" "no"))
351132718Skan  "core")
35290075Sobrien
353132718Skan(define_insn_reservation "load_or_store" 2
354132718Skan  (and (eq_attr "ldsched" "!yes") (eq_attr "type" "load,store1"))
355132718Skan  "core*2")
356132718Skan
357132718Skan(define_insn_reservation "mult" 16
358132718Skan  (and (eq_attr "ldsched" "no") (eq_attr "type" "mult"))
359132718Skan  "core*16")
360132718Skan
361132718Skan(define_insn_reservation "mult_ldsched_strongarm" 3
36290075Sobrien  (and (and (eq_attr "ldsched" "yes") (eq_attr "is_strongarm" "yes"))
363132718Skan       (eq_attr "type" "mult"))
364132718Skan  "core*2")
36590075Sobrien
366132718Skan(define_insn_reservation "mult_ldsched" 4
367132718Skan  (and (and (eq_attr "ldsched" "yes") (eq_attr "is_strongarm" "no"))
368132718Skan       (eq_attr "type" "mult"))
369132718Skan  "core*4")
37090075Sobrien
371132718Skan(define_insn_reservation "multi_cycle" 32
372132718Skan  (and (eq_attr "core_cycles" "multi")
373132718Skan       (eq_attr "type" "!mult,load,store1,store2,store3,store4"))
374132718Skan  "core*32")
37590075Sobrien
376132718Skan(define_insn_reservation "single_cycle" 1
377132718Skan  (eq_attr "core_cycles" "single")
378132718Skan  "core")
37990075Sobrien
38090075Sobrien
38190075Sobrien;;---------------------------------------------------------------------------
38290075Sobrien;; Insn patterns
38390075Sobrien;;
38490075Sobrien;; Addition insns.
38590075Sobrien
38690075Sobrien;; Note: For DImode insns, there is normally no reason why operands should
38790075Sobrien;; not be in the same register, what we don't want is for something being
38890075Sobrien;; written to partially overlap something that is an input.
389132718Skan;; Cirrus 64bit additions should not be split because we have a native
390132718Skan;; 64bit addition instructions.
39190075Sobrien
39290075Sobrien(define_expand "adddi3"
39390075Sobrien [(parallel
39490075Sobrien   [(set (match_operand:DI           0 "s_register_operand" "")
39590075Sobrien	  (plus:DI (match_operand:DI 1 "s_register_operand" "")
39690075Sobrien	           (match_operand:DI 2 "s_register_operand" "")))
39790075Sobrien    (clobber (reg:CC CC_REGNUM))])]
39890075Sobrien  "TARGET_EITHER"
39990075Sobrien  "
400132718Skan  if (TARGET_CIRRUS)
401132718Skan    {
402132718Skan      if (!cirrus_fp_register (operands[0], DImode))
403132718Skan        operands[0] = force_reg (DImode, operands[0]);
404132718Skan      if (!cirrus_fp_register (operands[1], DImode))
405132718Skan        operands[1] = force_reg (DImode, operands[1]);
406132718Skan      emit_insn (gen_cirrus_adddi3 (operands[0], operands[1], operands[2]));
407132718Skan      DONE;
408132718Skan    }
409132718Skan
41090075Sobrien  if (TARGET_THUMB)
41190075Sobrien    {
41290075Sobrien      if (GET_CODE (operands[1]) != REG)
41390075Sobrien        operands[1] = force_reg (SImode, operands[1]);
41490075Sobrien      if (GET_CODE (operands[2]) != REG)
41590075Sobrien        operands[2] = force_reg (SImode, operands[2]);
41690075Sobrien     }
41790075Sobrien  "
41890075Sobrien)
41990075Sobrien
42090075Sobrien(define_insn "*thumb_adddi3"
42190075Sobrien  [(set (match_operand:DI          0 "register_operand" "=l")
42290075Sobrien	(plus:DI (match_operand:DI 1 "register_operand" "%0")
42390075Sobrien		 (match_operand:DI 2 "register_operand" "l")))
42490075Sobrien   (clobber (reg:CC CC_REGNUM))
42590075Sobrien  ]
42690075Sobrien  "TARGET_THUMB"
42790075Sobrien  "add\\t%Q0, %Q0, %Q2\;adc\\t%R0, %R0, %R2"
42890075Sobrien  [(set_attr "length" "4")]
42990075Sobrien)
43090075Sobrien
43190075Sobrien(define_insn_and_split "*arm_adddi3"
43290075Sobrien  [(set (match_operand:DI          0 "s_register_operand" "=&r,&r")
43390075Sobrien	(plus:DI (match_operand:DI 1 "s_register_operand" "%0, 0")
43490075Sobrien		 (match_operand:DI 2 "s_register_operand" "r,  0")))
43590075Sobrien   (clobber (reg:CC CC_REGNUM))]
436132718Skan  "TARGET_ARM && !TARGET_CIRRUS"
43790075Sobrien  "#"
43890075Sobrien  "TARGET_ARM && reload_completed"
43990075Sobrien  [(parallel [(set (reg:CC_C CC_REGNUM)
44090075Sobrien		   (compare:CC_C (plus:SI (match_dup 1) (match_dup 2))
44190075Sobrien				 (match_dup 1)))
44290075Sobrien	      (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))])
44390075Sobrien   (set (match_dup 3) (plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))
44490075Sobrien			       (plus:SI (match_dup 4) (match_dup 5))))]
44590075Sobrien  "
44690075Sobrien  {
44790075Sobrien    operands[3] = gen_highpart (SImode, operands[0]);
44890075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
44990075Sobrien    operands[4] = gen_highpart (SImode, operands[1]);
45090075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
45190075Sobrien    operands[5] = gen_highpart (SImode, operands[2]);
45290075Sobrien    operands[2] = gen_lowpart (SImode, operands[2]);
45390075Sobrien  }"
45490075Sobrien  [(set_attr "conds" "clob")
45590075Sobrien   (set_attr "length" "8")]
45690075Sobrien)
45790075Sobrien
45890075Sobrien(define_insn_and_split "*adddi_sesidi_di"
45990075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
46090075Sobrien	(plus:DI (sign_extend:DI
46190075Sobrien		  (match_operand:SI 2 "s_register_operand" "r,r"))
46290075Sobrien		 (match_operand:DI 1 "s_register_operand" "r,0")))
46390075Sobrien   (clobber (reg:CC CC_REGNUM))]
464132718Skan  "TARGET_ARM && !TARGET_CIRRUS"
46590075Sobrien  "#"
46690075Sobrien  "TARGET_ARM && reload_completed"
46790075Sobrien  [(parallel [(set (reg:CC_C CC_REGNUM)
46890075Sobrien		   (compare:CC_C (plus:SI (match_dup 1) (match_dup 2))
46990075Sobrien				 (match_dup 1)))
47090075Sobrien	      (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))])
47190075Sobrien   (set (match_dup 3) (plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))
47290075Sobrien			       (plus:SI (ashiftrt:SI (match_dup 2)
47390075Sobrien						     (const_int 31))
47490075Sobrien					(match_dup 4))))]
47590075Sobrien  "
47690075Sobrien  {
47790075Sobrien    operands[3] = gen_highpart (SImode, operands[0]);
47890075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
47990075Sobrien    operands[4] = gen_highpart (SImode, operands[1]);
48090075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
48190075Sobrien    operands[2] = gen_lowpart (SImode, operands[2]);
48290075Sobrien  }"
48390075Sobrien  [(set_attr "conds" "clob")
48490075Sobrien   (set_attr "length" "8")]
48590075Sobrien)
48690075Sobrien
48790075Sobrien(define_insn_and_split "*adddi_zesidi_di"
48890075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
48990075Sobrien	(plus:DI (zero_extend:DI
49090075Sobrien		  (match_operand:SI 2 "s_register_operand" "r,r"))
49190075Sobrien		 (match_operand:DI 1 "s_register_operand" "r,0")))
49290075Sobrien   (clobber (reg:CC CC_REGNUM))]
493132718Skan  "TARGET_ARM && !TARGET_CIRRUS"
49490075Sobrien  "#"
49590075Sobrien  "TARGET_ARM && reload_completed"
49690075Sobrien  [(parallel [(set (reg:CC_C CC_REGNUM)
49790075Sobrien		   (compare:CC_C (plus:SI (match_dup 1) (match_dup 2))
49890075Sobrien				 (match_dup 1)))
49990075Sobrien	      (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))])
50090075Sobrien   (set (match_dup 3) (plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))
50190075Sobrien			       (plus:SI (match_dup 4) (const_int 0))))]
50290075Sobrien  "
50390075Sobrien  {
50490075Sobrien    operands[3] = gen_highpart (SImode, operands[0]);
50590075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
50690075Sobrien    operands[4] = gen_highpart (SImode, operands[1]);
50790075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
50890075Sobrien    operands[2] = gen_lowpart (SImode, operands[2]);
50990075Sobrien  }"
51090075Sobrien  [(set_attr "conds" "clob")
51190075Sobrien   (set_attr "length" "8")]
51290075Sobrien)
51390075Sobrien
51490075Sobrien(define_expand "addsi3"
51590075Sobrien  [(set (match_operand:SI          0 "s_register_operand" "")
51690075Sobrien	(plus:SI (match_operand:SI 1 "s_register_operand" "")
51790075Sobrien		 (match_operand:SI 2 "reg_or_int_operand" "")))]
51890075Sobrien  "TARGET_EITHER"
51990075Sobrien  "
52090075Sobrien  if (TARGET_ARM && GET_CODE (operands[2]) == CONST_INT)
52190075Sobrien    {
52290075Sobrien      arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0],
52390075Sobrien			  operands[1],
52490075Sobrien			  (no_new_pseudos ? 0 : preserve_subexpressions_p ()));
52590075Sobrien      DONE;
52690075Sobrien    }
52790075Sobrien  "
52890075Sobrien)
52990075Sobrien
530132718Skan; If there is a scratch available, this will be faster than synthesizing the
53190075Sobrien; addition.
53290075Sobrien(define_peephole2
53390075Sobrien  [(match_scratch:SI 3 "r")
53490075Sobrien   (set (match_operand:SI          0 "s_register_operand" "")
53590075Sobrien	(plus:SI (match_operand:SI 1 "s_register_operand" "")
53690075Sobrien		 (match_operand:SI 2 "const_int_operand"  "")))]
53790075Sobrien  "TARGET_ARM &&
53890075Sobrien   !(const_ok_for_arm (INTVAL (operands[2]))
53990075Sobrien     || const_ok_for_arm (-INTVAL (operands[2])))
54090075Sobrien    && const_ok_for_arm (~INTVAL (operands[2]))"
54190075Sobrien  [(set (match_dup 3) (match_dup 2))
54290075Sobrien   (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 3)))]
54390075Sobrien  ""
54490075Sobrien)
54590075Sobrien
54690075Sobrien(define_insn_and_split "*arm_addsi3"
54790075Sobrien  [(set (match_operand:SI          0 "s_register_operand" "=r,r,r")
54890075Sobrien	(plus:SI (match_operand:SI 1 "s_register_operand" "%r,r,r")
54990075Sobrien		 (match_operand:SI 2 "reg_or_int_operand" "rI,L,?n")))]
55090075Sobrien  "TARGET_ARM"
55190075Sobrien  "@
55290075Sobrien   add%?\\t%0, %1, %2
55390075Sobrien   sub%?\\t%0, %1, #%n2
55490075Sobrien   #"
55590075Sobrien  "TARGET_ARM &&
55690075Sobrien   GET_CODE (operands[2]) == CONST_INT
55790075Sobrien   && !(const_ok_for_arm (INTVAL (operands[2]))
55890075Sobrien        || const_ok_for_arm (-INTVAL (operands[2])))"
55990075Sobrien  [(clobber (const_int 0))]
56090075Sobrien  "
56190075Sobrien  arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0],
56290075Sobrien		      operands[1], 0);
56390075Sobrien  DONE;
56490075Sobrien  "
56590075Sobrien  [(set_attr "length" "4,4,16")
56690075Sobrien   (set_attr "predicable" "yes")]
56790075Sobrien)
56890075Sobrien
56990075Sobrien;; Register group 'k' is a single register group containing only the stack
57090075Sobrien;; register.  Trying to reload it will always fail catastrophically,
57190075Sobrien;; so never allow those alternatives to match if reloading is needed.
57290075Sobrien
57390075Sobrien(define_insn "*thumb_addsi3"
57490075Sobrien  [(set (match_operand:SI          0 "register_operand" "=l,l,l,*r,*h,l,!k")
57590075Sobrien	(plus:SI (match_operand:SI 1 "register_operand" "%0,0,l,*0,*0,!k,!k")
57690075Sobrien		 (match_operand:SI 2 "nonmemory_operand" "I,J,lL,*h,*r,!M,!O")))]
57790075Sobrien  "TARGET_THUMB"
57890075Sobrien  "*
57990075Sobrien   static const char * const asms[] = 
58090075Sobrien   {
58190075Sobrien     \"add\\t%0, %0, %2\",
58290075Sobrien     \"sub\\t%0, %0, #%n2\",
58390075Sobrien     \"add\\t%0, %1, %2\",
58490075Sobrien     \"add\\t%0, %0, %2\",
58590075Sobrien     \"add\\t%0, %0, %2\",
58690075Sobrien     \"add\\t%0, %1, %2\",
58790075Sobrien     \"add\\t%0, %1, %2\"
58890075Sobrien   };
58990075Sobrien   if ((which_alternative == 2 || which_alternative == 6)
59090075Sobrien       && GET_CODE (operands[2]) == CONST_INT
59190075Sobrien       && INTVAL (operands[2]) < 0)
59290075Sobrien     return \"sub\\t%0, %1, #%n2\";
59390075Sobrien   return asms[which_alternative];
59490075Sobrien  "
59590075Sobrien  [(set_attr "length" "2")]
59690075Sobrien)
59790075Sobrien
59890075Sobrien;; Reloading and elimination of the frame pointer can
59990075Sobrien;; sometimes cause this optimization to be missed.
60090075Sobrien(define_peephole2
601117395Skan  [(set (match_operand:SI 0 "register_operand" "")
602117395Skan	(match_operand:SI 1 "const_int_operand" ""))
60390075Sobrien   (set (match_dup 0)
604117395Skan	(plus:SI (match_dup 0) (match_operand:SI 2 "register_operand" "")))]
60590075Sobrien  "TARGET_THUMB
60690075Sobrien   && REGNO (operands[2]) == STACK_POINTER_REGNUM 
60790075Sobrien   && (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) < 1024
60890075Sobrien   && (INTVAL (operands[1]) & 3) == 0"
60990075Sobrien  [(set (match_dup 0) (plus:SI (match_dup 2) (match_dup 1)))]
61090075Sobrien  ""
61190075Sobrien)
61290075Sobrien
61390075Sobrien(define_insn "*addsi3_compare0"
61490075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
61590075Sobrien	(compare:CC_NOOV
61690075Sobrien	 (plus:SI (match_operand:SI 1 "s_register_operand" "r, r")
61790075Sobrien		  (match_operand:SI 2 "arm_add_operand"    "rI,L"))
61890075Sobrien	 (const_int 0)))
61990075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r,r")
62090075Sobrien	(plus:SI (match_dup 1) (match_dup 2)))]
62190075Sobrien  "TARGET_ARM"
62290075Sobrien  "@
62390075Sobrien   add%?s\\t%0, %1, %2
62490075Sobrien   sub%?s\\t%0, %1, #%n2"
62590075Sobrien  [(set_attr "conds" "set")]
62690075Sobrien)
62790075Sobrien
62890075Sobrien(define_insn "*addsi3_compare0_scratch"
62990075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
63090075Sobrien	(compare:CC_NOOV
63190075Sobrien	 (plus:SI (match_operand:SI 0 "s_register_operand" "r, r")
63290075Sobrien		  (match_operand:SI 1 "arm_add_operand"    "rI,L"))
63390075Sobrien	 (const_int 0)))]
63490075Sobrien  "TARGET_ARM"
63590075Sobrien  "@
63690075Sobrien   cmn%?\\t%0, %1
63790075Sobrien   cmp%?\\t%0, #%n1"
63890075Sobrien  [(set_attr "conds" "set")]
63990075Sobrien)
64090075Sobrien
64190075Sobrien;; These patterns are the same ones as the two regular addsi3_compare0
64290075Sobrien;; patterns, except we write them slightly different - the combiner
64390075Sobrien;; tends to generate them this way.
64490075Sobrien(define_insn "*addsi3_compare0_for_combiner"
64590075Sobrien  [(set (reg:CC CC_REGNUM)
64690075Sobrien	(compare:CC
64790075Sobrien	 (match_operand:SI 1 "s_register_operand" "r,r")
64890075Sobrien	 (neg:SI (match_operand:SI 2 "arm_add_operand" "rI,L"))))
64990075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r,r")
65090075Sobrien	(plus:SI (match_dup 1) (match_dup 2)))]
65190075Sobrien  "TARGET_ARM"
65290075Sobrien  "@
65390075Sobrien   add%?s\\t%0, %1, %2
65490075Sobrien   sub%?s\\t%0, %1, #%n2"
65590075Sobrien  [(set_attr "conds" "set")]
65690075Sobrien)
65790075Sobrien
65890075Sobrien(define_insn "*addsi3_compare0_scratch_for_combiner"
65990075Sobrien  [(set (reg:CC CC_REGNUM)
66090075Sobrien	(compare:CC
66190075Sobrien	 (match_operand:SI 0 "s_register_operand" "r,r")
66290075Sobrien	 (neg:SI (match_operand:SI 1 "arm_add_operand" "rI,L"))))]
66390075Sobrien  "TARGET_ARM"
66490075Sobrien  "@
66590075Sobrien   cmn%?\\t%0, %1
66690075Sobrien   cmp%?\\t%0, #%n1"
66790075Sobrien  [(set_attr "conds" "set")]
66890075Sobrien)
66990075Sobrien
670132718Skan;; This is the canonicalization of addsi3_compare0_for_combiner when the
671132718Skan;; addend is a constant.
672132718Skan(define_insn "*cmpsi2_addneg"
673132718Skan  [(set (reg:CC CC_REGNUM)
674132718Skan	(compare:CC
675132718Skan	 (match_operand:SI 1 "s_register_operand" "r,r")
676132718Skan	 (match_operand:SI 2 "arm_addimm_operand" "I,L")))
677132718Skan   (set (match_operand:SI 0 "s_register_operand" "=r,r")
678132718Skan	(plus:SI (match_dup 1)
679132718Skan		 (match_operand:SI 3 "arm_addimm_operand" "L,I")))]
680132718Skan  "TARGET_ARM && INTVAL (operands[2]) == -INTVAL (operands[3])"
681132718Skan  "@
682132718Skan   sub%?s\\t%0, %1, %2
683132718Skan   add%?s\\t%0, %1, #%n2"
684132718Skan  [(set_attr "conds" "set")]
685132718Skan)
686132718Skan
687132718Skan;; Convert the sequence
688132718Skan;;  sub  rd, rn, #1
689132718Skan;;  cmn  rd, #1	(equivalent to cmp rd, #-1)
690132718Skan;;  bne  dest
691132718Skan;; into
692132718Skan;;  subs rd, rn, #1
693132718Skan;;  bcs  dest	((unsigned)rn >= 1)
694132718Skan;; similarly for the beq variant using bcc.
695132718Skan;; This is a common looping idiom (while (n--))
696132718Skan(define_peephole2
697132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
698132718Skan	(plus:SI (match_operand:SI 1 "s_register_operand" "")
699132718Skan		 (const_int -1)))
700132718Skan   (set (match_operand 2 "cc_register" "")
701132718Skan	(compare (match_dup 0) (const_int -1)))
702132718Skan   (set (pc)
703132718Skan	(if_then_else (match_operator 3 "equality_operator"
704132718Skan		       [(match_dup 2) (const_int 0)])
705132718Skan		      (match_operand 4 "" "")
706132718Skan		      (match_operand 5 "" "")))]
707132718Skan  "TARGET_ARM && peep2_reg_dead_p (3, operands[2])"
708132718Skan  [(parallel[
709132718Skan    (set (match_dup 2)
710132718Skan	 (compare:CC
711132718Skan	  (match_dup 1) (const_int 1)))
712132718Skan    (set (match_dup 0) (plus:SI (match_dup 1) (const_int -1)))])
713132718Skan   (set (pc)
714132718Skan	(if_then_else (match_op_dup 3 [(match_dup 2) (const_int 0)])
715132718Skan		      (match_dup 4)
716132718Skan		      (match_dup 5)))]
717132718Skan  "operands[2] = gen_rtx_REG (CCmode, CC_REGNUM);
718132718Skan   operands[3] = gen_rtx_fmt_ee ((GET_CODE (operands[3]) == NE
719132718Skan				  ? GEU : LTU),
720132718Skan				 VOIDmode, 
721132718Skan				 operands[2], const0_rtx);"
722132718Skan)
723132718Skan
72490075Sobrien;; The next four insns work because they compare the result with one of
72590075Sobrien;; the operands, and we know that the use of the condition code is
72690075Sobrien;; either GEU or LTU, so we can use the carry flag from the addition
72790075Sobrien;; instead of doing the compare a second time.
72890075Sobrien(define_insn "*addsi3_compare_op1"
72990075Sobrien  [(set (reg:CC_C CC_REGNUM)
73090075Sobrien	(compare:CC_C
73190075Sobrien	 (plus:SI (match_operand:SI 1 "s_register_operand" "r,r")
73290075Sobrien		  (match_operand:SI 2 "arm_add_operand" "rI,L"))
73390075Sobrien	 (match_dup 1)))
73490075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r,r")
73590075Sobrien	(plus:SI (match_dup 1) (match_dup 2)))]
73690075Sobrien  "TARGET_ARM"
73790075Sobrien  "@
73890075Sobrien   add%?s\\t%0, %1, %2
73990075Sobrien   sub%?s\\t%0, %1, #%n2"
74090075Sobrien  [(set_attr "conds" "set")]
74190075Sobrien)
74290075Sobrien
74390075Sobrien(define_insn "*addsi3_compare_op2"
74490075Sobrien  [(set (reg:CC_C CC_REGNUM)
74590075Sobrien	(compare:CC_C
74690075Sobrien	 (plus:SI (match_operand:SI 1 "s_register_operand" "r,r")
74790075Sobrien		  (match_operand:SI 2 "arm_add_operand" "rI,L"))
74890075Sobrien	 (match_dup 2)))
74990075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r,r")
75090075Sobrien	(plus:SI (match_dup 1) (match_dup 2)))]
75190075Sobrien  "TARGET_ARM"
75290075Sobrien  "@
75390075Sobrien   add%?s\\t%0, %1, %2
75490075Sobrien   sub%?s\\t%0, %1, #%n2"
75590075Sobrien  [(set_attr "conds" "set")]
75690075Sobrien)
75790075Sobrien
75890075Sobrien(define_insn "*compare_addsi2_op0"
75990075Sobrien  [(set (reg:CC_C CC_REGNUM)
76090075Sobrien	(compare:CC_C
76190075Sobrien	 (plus:SI (match_operand:SI 0 "s_register_operand" "r,r")
76290075Sobrien		  (match_operand:SI 1 "arm_add_operand" "rI,L"))
76390075Sobrien	 (match_dup 0)))]
76490075Sobrien  "TARGET_ARM"
76590075Sobrien  "@
76690075Sobrien   cmn%?\\t%0, %1
76790075Sobrien   cmp%?\\t%0, #%n1"
76890075Sobrien  [(set_attr "conds" "set")]
76990075Sobrien)
77090075Sobrien
77190075Sobrien(define_insn "*compare_addsi2_op1"
77290075Sobrien  [(set (reg:CC_C CC_REGNUM)
77390075Sobrien	(compare:CC_C
77490075Sobrien	 (plus:SI (match_operand:SI 0 "s_register_operand" "r,r")
77590075Sobrien		  (match_operand:SI 1 "arm_add_operand" "rI,L"))
77690075Sobrien	 (match_dup 1)))]
77790075Sobrien  "TARGET_ARM"
77890075Sobrien  "@
77990075Sobrien   cmn%?\\t%0, %1
78090075Sobrien   cmp%?\\t%0, #%n1"
78190075Sobrien  [(set_attr "conds" "set")]
78290075Sobrien)
78390075Sobrien
78490075Sobrien(define_insn "*addsi3_carryin"
78590075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
78690075Sobrien	(plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))
78790075Sobrien		 (plus:SI (match_operand:SI 1 "s_register_operand" "r")
78890075Sobrien			  (match_operand:SI 2 "arm_rhs_operand" "rI"))))]
78990075Sobrien  "TARGET_ARM"
79090075Sobrien  "adc%?\\t%0, %1, %2"
79190075Sobrien  [(set_attr "conds" "use")]
79290075Sobrien)
79390075Sobrien
79490075Sobrien(define_insn "*addsi3_carryin_shift"
795132718Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
79690075Sobrien	(plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))
79790075Sobrien		 (plus:SI
79890075Sobrien		   (match_operator:SI 2 "shift_operator"
799132718Skan		      [(match_operand:SI 3 "s_register_operand" "r")
800132718Skan		       (match_operand:SI 4 "reg_or_int_operand" "rM")])
801132718Skan		    (match_operand:SI 1 "s_register_operand" "r"))))]
80290075Sobrien  "TARGET_ARM"
80390075Sobrien  "adc%?\\t%0, %1, %3%S2"
80490075Sobrien  [(set_attr "conds" "use")]
80590075Sobrien)
80690075Sobrien
80790075Sobrien(define_insn "*addsi3_carryin_alt1"
80890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
80990075Sobrien	(plus:SI (plus:SI (match_operand:SI 1 "s_register_operand" "r")
81090075Sobrien			  (match_operand:SI 2 "arm_rhs_operand" "rI"))
81190075Sobrien		 (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))))]
81290075Sobrien  "TARGET_ARM"
81390075Sobrien  "adc%?\\t%0, %1, %2"
81490075Sobrien  [(set_attr "conds" "use")]
81590075Sobrien)
81690075Sobrien
81790075Sobrien(define_insn "*addsi3_carryin_alt2"
81890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
81990075Sobrien	(plus:SI (plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))
82090075Sobrien			  (match_operand:SI 1 "s_register_operand" "r"))
82190075Sobrien		 (match_operand:SI 2 "arm_rhs_operand" "rI")))]
82290075Sobrien  "TARGET_ARM"
82390075Sobrien  "adc%?\\t%0, %1, %2"
82490075Sobrien  [(set_attr "conds" "use")]
82590075Sobrien)
82690075Sobrien
82790075Sobrien(define_insn "*addsi3_carryin_alt3"
82890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
82990075Sobrien	(plus:SI (plus:SI (ltu:SI (reg:CC_C CC_REGNUM) (const_int 0))
83090075Sobrien			  (match_operand:SI 2 "arm_rhs_operand" "rI"))
83190075Sobrien		 (match_operand:SI 1 "s_register_operand" "r")))]
83290075Sobrien  "TARGET_ARM"
83390075Sobrien  "adc%?\\t%0, %1, %2"
83490075Sobrien  [(set_attr "conds" "use")]
83590075Sobrien)
83690075Sobrien
83790075Sobrien(define_insn "incscc"
83890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
83990075Sobrien        (plus:SI (match_operator:SI 2 "arm_comparison_operator"
84090075Sobrien                    [(match_operand:CC 3 "cc_register" "") (const_int 0)])
84190075Sobrien                 (match_operand:SI 1 "s_register_operand" "0,?r")))]
84290075Sobrien  "TARGET_ARM"
84390075Sobrien  "@
84490075Sobrien  add%d2\\t%0, %1, #1
84590075Sobrien  mov%D2\\t%0, %1\;add%d2\\t%0, %1, #1"
84690075Sobrien  [(set_attr "conds" "use")
84790075Sobrien   (set_attr "length" "4,8")]
84890075Sobrien)
84990075Sobrien
850132718Skan; transform ((x << y) - 1) to ~(~(x-1) << y)  Where X is a constant.
851132718Skan(define_split
852132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
853132718Skan	(plus:SI (ashift:SI (match_operand:SI 1 "const_int_operand" "")
854132718Skan			    (match_operand:SI 2 "s_register_operand" ""))
855132718Skan		 (const_int -1)))
856132718Skan   (clobber (match_operand:SI 3 "s_register_operand" ""))]
857132718Skan  "TARGET_ARM"
858132718Skan  [(set (match_dup 3) (match_dup 1))
859132718Skan   (set (match_dup 0) (not:SI (ashift:SI (match_dup 3) (match_dup 2))))]
860132718Skan  "
861132718Skan  operands[1] = GEN_INT (~(INTVAL (operands[1]) - 1));
862132718Skan")
86390075Sobrien
864132718Skan(define_expand "addsf3"
865132718Skan  [(set (match_operand:SF          0 "s_register_operand" "")
866132718Skan	(plus:SF (match_operand:SF 1 "s_register_operand" "")
867132718Skan		 (match_operand:SF 2 "fpa_add_operand" "")))]
868132718Skan  "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
869132718Skan  "
870132718Skan  if (TARGET_CIRRUS
871132718Skan      && !cirrus_fp_register (operands[2], SFmode))
872132718Skan    operands[2] = force_reg (SFmode, operands[2]);
873132718Skan")
87490075Sobrien
875132718Skan(define_expand "adddf3"
876132718Skan  [(set (match_operand:DF          0 "s_register_operand" "")
877132718Skan	(plus:DF (match_operand:DF 1 "s_register_operand" "")
878132718Skan		 (match_operand:DF 2 "fpa_add_operand" "")))]
879132718Skan  "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
880132718Skan  "
881132718Skan  if (TARGET_CIRRUS
882132718Skan      && !cirrus_fp_register (operands[2], DFmode))
883132718Skan    operands[2] = force_reg (DFmode, operands[2]);
884132718Skan")
88590075Sobrien
88690075Sobrien(define_expand "subdi3"
88790075Sobrien [(parallel
88890075Sobrien   [(set (match_operand:DI            0 "s_register_operand" "")
88990075Sobrien	  (minus:DI (match_operand:DI 1 "s_register_operand" "")
89090075Sobrien	            (match_operand:DI 2 "s_register_operand" "")))
89190075Sobrien    (clobber (reg:CC CC_REGNUM))])]
89290075Sobrien  "TARGET_EITHER"
89390075Sobrien  "
894132718Skan  if (TARGET_CIRRUS
895132718Skan      && TARGET_ARM
896132718Skan      && cirrus_fp_register (operands[0], DImode)
897132718Skan      && cirrus_fp_register (operands[1], DImode))
898132718Skan    {
899132718Skan      emit_insn (gen_cirrus_subdi3 (operands[0], operands[1], operands[2]));
900132718Skan      DONE;
901132718Skan    }
902132718Skan
90390075Sobrien  if (TARGET_THUMB)
90490075Sobrien    {
90590075Sobrien      if (GET_CODE (operands[1]) != REG)
90690075Sobrien        operands[1] = force_reg (SImode, operands[1]);
90790075Sobrien      if (GET_CODE (operands[2]) != REG)
90890075Sobrien        operands[2] = force_reg (SImode, operands[2]);
90990075Sobrien     }	
91090075Sobrien  "
91190075Sobrien)
91290075Sobrien
91390075Sobrien(define_insn "*arm_subdi3"
91490075Sobrien  [(set (match_operand:DI           0 "s_register_operand" "=&r,&r,&r")
91590075Sobrien	(minus:DI (match_operand:DI 1 "s_register_operand" "0,r,0")
91690075Sobrien		  (match_operand:DI 2 "s_register_operand" "r,0,0")))
91790075Sobrien   (clobber (reg:CC CC_REGNUM))]
91890075Sobrien  "TARGET_ARM"
91990075Sobrien  "subs\\t%Q0, %Q1, %Q2\;sbc\\t%R0, %R1, %R2"
92090075Sobrien  [(set_attr "conds" "clob")
92190075Sobrien   (set_attr "length" "8")]
92290075Sobrien)
92390075Sobrien
92490075Sobrien(define_insn "*thumb_subdi3"
92590075Sobrien  [(set (match_operand:DI           0 "register_operand" "=l")
92690075Sobrien	(minus:DI (match_operand:DI 1 "register_operand"  "0")
92790075Sobrien		  (match_operand:DI 2 "register_operand"  "l")))
92890075Sobrien   (clobber (reg:CC CC_REGNUM))]
92990075Sobrien  "TARGET_THUMB"
93090075Sobrien  "sub\\t%Q0, %Q0, %Q2\;sbc\\t%R0, %R0, %R2"
93190075Sobrien  [(set_attr "length" "4")]
93290075Sobrien)
93390075Sobrien
93490075Sobrien(define_insn "*subdi_di_zesidi"
93590075Sobrien  [(set (match_operand:DI           0 "s_register_operand" "=&r,&r")
93690075Sobrien	(minus:DI (match_operand:DI 1 "s_register_operand"  "?r,0")
93790075Sobrien		  (zero_extend:DI
93890075Sobrien		   (match_operand:SI 2 "s_register_operand"  "r,r"))))
93990075Sobrien   (clobber (reg:CC CC_REGNUM))]
94090075Sobrien  "TARGET_ARM"
94190075Sobrien  "subs\\t%Q0, %Q1, %2\;sbc\\t%R0, %R1, #0"
94290075Sobrien  [(set_attr "conds" "clob")
94390075Sobrien   (set_attr "length" "8")]
94490075Sobrien)
94590075Sobrien
94690075Sobrien(define_insn "*subdi_di_sesidi"
94790075Sobrien  [(set (match_operand:DI            0 "s_register_operand" "=&r,&r")
94890075Sobrien	(minus:DI (match_operand:DI  1 "s_register_operand"  "r,0")
94990075Sobrien		  (sign_extend:DI
95090075Sobrien		   (match_operand:SI 2 "s_register_operand"  "r,r"))))
95190075Sobrien   (clobber (reg:CC CC_REGNUM))]
95290075Sobrien  "TARGET_ARM"
95390075Sobrien  "subs\\t%Q0, %Q1, %2\;sbc\\t%R0, %R1, %2, asr #31"
95490075Sobrien  [(set_attr "conds" "clob")
95590075Sobrien   (set_attr "length" "8")]
95690075Sobrien)
95790075Sobrien
95890075Sobrien(define_insn "*subdi_zesidi_di"
95990075Sobrien  [(set (match_operand:DI            0 "s_register_operand" "=&r,&r")
96090075Sobrien	(minus:DI (zero_extend:DI
96190075Sobrien		   (match_operand:SI 2 "s_register_operand"  "r,r"))
96290075Sobrien		  (match_operand:DI  1 "s_register_operand" "?r,0")))
96390075Sobrien   (clobber (reg:CC CC_REGNUM))]
96490075Sobrien  "TARGET_ARM"
96590075Sobrien  "rsbs\\t%Q0, %Q1, %2\;rsc\\t%R0, %R1, #0"
96690075Sobrien  [(set_attr "conds" "clob")
96790075Sobrien   (set_attr "length" "8")]
96890075Sobrien)
96990075Sobrien
97090075Sobrien(define_insn "*subdi_sesidi_di"
97190075Sobrien  [(set (match_operand:DI            0 "s_register_operand" "=&r,&r")
97290075Sobrien	(minus:DI (sign_extend:DI
97390075Sobrien		   (match_operand:SI 2 "s_register_operand"   "r,r"))
97490075Sobrien		  (match_operand:DI  1 "s_register_operand"  "?r,0")))
97590075Sobrien   (clobber (reg:CC CC_REGNUM))]
97690075Sobrien  "TARGET_ARM"
97790075Sobrien  "rsbs\\t%Q0, %Q1, %2\;rsc\\t%R0, %R1, %2, asr #31"
97890075Sobrien  [(set_attr "conds" "clob")
97990075Sobrien   (set_attr "length" "8")]
98090075Sobrien)
98190075Sobrien
98290075Sobrien(define_insn "*subdi_zesidi_zesidi"
98390075Sobrien  [(set (match_operand:DI            0 "s_register_operand" "=r")
98490075Sobrien	(minus:DI (zero_extend:DI
98590075Sobrien		   (match_operand:SI 1 "s_register_operand"  "r"))
98690075Sobrien		  (zero_extend:DI
98790075Sobrien		   (match_operand:SI 2 "s_register_operand"  "r"))))
98890075Sobrien   (clobber (reg:CC CC_REGNUM))]
98990075Sobrien  "TARGET_ARM"
99090075Sobrien  "subs\\t%Q0, %1, %2\;rsc\\t%R0, %1, %1"
99190075Sobrien  [(set_attr "conds" "clob")
99290075Sobrien   (set_attr "length" "8")]
99390075Sobrien)
99490075Sobrien
99590075Sobrien(define_expand "subsi3"
99690075Sobrien  [(set (match_operand:SI           0 "s_register_operand" "")
99790075Sobrien	(minus:SI (match_operand:SI 1 "reg_or_int_operand" "")
99890075Sobrien		  (match_operand:SI 2 "s_register_operand" "")))]
99990075Sobrien  "TARGET_EITHER"
100090075Sobrien  "
100190075Sobrien  if (GET_CODE (operands[1]) == CONST_INT)
100290075Sobrien    {
100390075Sobrien      if (TARGET_ARM)
100490075Sobrien        {
100590075Sobrien          arm_split_constant (MINUS, SImode, INTVAL (operands[1]), operands[0],
100690075Sobrien	  		      operands[2],
100790075Sobrien			      (no_new_pseudos ? 0
100890075Sobrien			       :  preserve_subexpressions_p ()));
100990075Sobrien          DONE;
101090075Sobrien	}
101190075Sobrien      else /* TARGET_THUMB */
101290075Sobrien        operands[1] = force_reg (SImode, operands[1]);
101390075Sobrien    }
101490075Sobrien  "
101590075Sobrien)
101690075Sobrien
101790075Sobrien(define_insn "*thumb_subsi3_insn"
101890075Sobrien  [(set (match_operand:SI           0 "register_operand" "=l")
101990075Sobrien	(minus:SI (match_operand:SI 1 "register_operand" "l")
102090075Sobrien		  (match_operand:SI 2 "register_operand" "l")))]
102190075Sobrien  "TARGET_THUMB"
102290075Sobrien  "sub\\t%0, %1, %2"
102390075Sobrien  [(set_attr "length" "2")]
102490075Sobrien)
102590075Sobrien
102690075Sobrien(define_insn_and_split "*arm_subsi3_insn"
102790075Sobrien  [(set (match_operand:SI           0 "s_register_operand" "=r,r")
102890075Sobrien	(minus:SI (match_operand:SI 1 "reg_or_int_operand" "rI,?n")
102990075Sobrien		  (match_operand:SI 2 "s_register_operand" "r,r")))]
103090075Sobrien  "TARGET_ARM"
103190075Sobrien  "@
103290075Sobrien   rsb%?\\t%0, %2, %1
103390075Sobrien   #"
103490075Sobrien  "TARGET_ARM
103590075Sobrien   && GET_CODE (operands[1]) == CONST_INT
103690075Sobrien   && !const_ok_for_arm (INTVAL (operands[1]))"
103790075Sobrien  [(clobber (const_int 0))]
103890075Sobrien  "
103990075Sobrien  arm_split_constant (MINUS, SImode, INTVAL (operands[1]), operands[0],
104090075Sobrien		      operands[2], 0);
104190075Sobrien  DONE;
104290075Sobrien  "
104390075Sobrien  [(set_attr "length" "4,16")
104490075Sobrien   (set_attr "predicable" "yes")]
104590075Sobrien)
104690075Sobrien
104790075Sobrien(define_peephole2
104890075Sobrien  [(match_scratch:SI 3 "r")
104990075Sobrien   (set (match_operand:SI           0 "s_register_operand" "")
105090075Sobrien	(minus:SI (match_operand:SI 1 "const_int_operand" "")
105190075Sobrien		  (match_operand:SI 2 "s_register_operand" "")))]
105290075Sobrien  "TARGET_ARM
105390075Sobrien   && !const_ok_for_arm (INTVAL (operands[1]))
105490075Sobrien   && const_ok_for_arm (~INTVAL (operands[1]))"
105590075Sobrien  [(set (match_dup 3) (match_dup 1))
105690075Sobrien   (set (match_dup 0) (minus:SI (match_dup 3) (match_dup 2)))]
105790075Sobrien  ""
105890075Sobrien)
105990075Sobrien
106090075Sobrien(define_insn "*subsi3_compare0"
106190075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
106290075Sobrien	(compare:CC_NOOV
106390075Sobrien	 (minus:SI (match_operand:SI 1 "arm_rhs_operand" "r,I")
106490075Sobrien		   (match_operand:SI 2 "arm_rhs_operand" "rI,r"))
106590075Sobrien	 (const_int 0)))
106690075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r,r")
106790075Sobrien	(minus:SI (match_dup 1) (match_dup 2)))]
106890075Sobrien  "TARGET_ARM"
106990075Sobrien  "@
107090075Sobrien   sub%?s\\t%0, %1, %2
107190075Sobrien   rsb%?s\\t%0, %2, %1"
107290075Sobrien  [(set_attr "conds" "set")]
107390075Sobrien)
107490075Sobrien
107590075Sobrien(define_insn "decscc"
107690075Sobrien  [(set (match_operand:SI            0 "s_register_operand" "=r,r")
107790075Sobrien        (minus:SI (match_operand:SI  1 "s_register_operand" "0,?r")
107890075Sobrien		  (match_operator:SI 2 "arm_comparison_operator"
107990075Sobrien                   [(match_operand   3 "cc_register" "") (const_int 0)])))]
108090075Sobrien  "TARGET_ARM"
108190075Sobrien  "@
108290075Sobrien   sub%d2\\t%0, %1, #1
108390075Sobrien   mov%D2\\t%0, %1\;sub%d2\\t%0, %1, #1"
108490075Sobrien  [(set_attr "conds" "use")
108590075Sobrien   (set_attr "length" "*,8")]
108690075Sobrien)
108790075Sobrien
1088132718Skan(define_expand "subsf3"
1089132718Skan  [(set (match_operand:SF           0 "s_register_operand" "")
1090132718Skan	(minus:SF (match_operand:SF 1 "fpa_rhs_operand" "")
1091132718Skan		  (match_operand:SF 2 "fpa_rhs_operand" "")))]
1092132718Skan  "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
1093132718Skan  "
1094132718Skan  if (TARGET_CIRRUS)
1095132718Skan    {
1096132718Skan      if (!cirrus_fp_register (operands[1], SFmode))
1097132718Skan        operands[1] = force_reg (SFmode, operands[1]);
1098132718Skan      if (!cirrus_fp_register (operands[2], SFmode))
1099132718Skan        operands[2] = force_reg (SFmode, operands[2]);
1100132718Skan    }
1101132718Skan")
110290075Sobrien
1103132718Skan(define_expand "subdf3"
1104132718Skan  [(set (match_operand:DF           0 "s_register_operand" "")
1105132718Skan	(minus:DF (match_operand:DF 1 "fpa_rhs_operand"     "")
1106132718Skan		  (match_operand:DF 2 "fpa_rhs_operand"    "")))]
1107132718Skan  "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
1108132718Skan  "
1109132718Skan  if (TARGET_CIRRUS)
1110132718Skan    {
1111132718Skan       if (!cirrus_fp_register (operands[1], DFmode))
1112132718Skan         operands[1] = force_reg (DFmode, operands[1]);
1113132718Skan       if (!cirrus_fp_register (operands[2], DFmode))
1114132718Skan         operands[2] = force_reg (DFmode, operands[2]);
1115132718Skan    }
1116132718Skan")
111790075Sobrien
111890075Sobrien
111990075Sobrien;; Multiplication insns
112090075Sobrien
112190075Sobrien(define_expand "mulsi3"
112290075Sobrien  [(set (match_operand:SI          0 "s_register_operand" "")
112390075Sobrien	(mult:SI (match_operand:SI 2 "s_register_operand" "")
112490075Sobrien		 (match_operand:SI 1 "s_register_operand" "")))]
112590075Sobrien  "TARGET_EITHER"
112690075Sobrien  ""
112790075Sobrien)
112890075Sobrien
112990075Sobrien;; Use `&' and then `0' to prevent the operands 0 and 1 being the same
113090075Sobrien(define_insn "*arm_mulsi3"
113190075Sobrien  [(set (match_operand:SI          0 "s_register_operand" "=&r,&r")
113290075Sobrien	(mult:SI (match_operand:SI 2 "s_register_operand" "r,r")
113390075Sobrien		 (match_operand:SI 1 "s_register_operand" "%?r,0")))]
113490075Sobrien  "TARGET_ARM"
113590075Sobrien  "mul%?\\t%0, %2, %1"
113690075Sobrien  [(set_attr "type" "mult")
113790075Sobrien   (set_attr "predicable" "yes")]
113890075Sobrien)
113990075Sobrien
114090075Sobrien; Unfortunately with the Thumb the '&'/'0' trick can fails when operands 
114190075Sobrien; 1 and 2; are the same, because reload will make operand 0 match 
114290075Sobrien; operand 1 without realizing that this conflicts with operand 2.  We fix 
114390075Sobrien; this by adding another alternative to match this case, and then `reload' 
114490075Sobrien; it ourselves.  This alternative must come first.
114590075Sobrien(define_insn "*thumb_mulsi3"
114690075Sobrien  [(set (match_operand:SI          0 "register_operand" "=&l,&l,&l")
114790075Sobrien	(mult:SI (match_operand:SI 1 "register_operand" "%l,*h,0")
114890075Sobrien		 (match_operand:SI 2 "register_operand" "l,l,l")))]
114990075Sobrien  "TARGET_THUMB"
115090075Sobrien  "*
115190075Sobrien  if (which_alternative < 2)
115290075Sobrien    return \"mov\\t%0, %1\;mul\\t%0, %0, %2\";
115390075Sobrien  else
115490075Sobrien    return \"mul\\t%0, %0, %2\";
115590075Sobrien  "
115690075Sobrien  [(set_attr "length" "4,4,2")
115790075Sobrien   (set_attr "type" "mult")]
115890075Sobrien)
115990075Sobrien
116090075Sobrien(define_insn "*mulsi3_compare0"
116190075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
116290075Sobrien	(compare:CC_NOOV (mult:SI
116390075Sobrien			  (match_operand:SI 2 "s_register_operand" "r,r")
116490075Sobrien			  (match_operand:SI 1 "s_register_operand" "%?r,0"))
116590075Sobrien			 (const_int 0)))
116690075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=&r,&r")
116790075Sobrien	(mult:SI (match_dup 2) (match_dup 1)))]
1168132718Skan  "TARGET_ARM && !arm_arch_xscale"
116990075Sobrien  "mul%?s\\t%0, %2, %1"
117090075Sobrien  [(set_attr "conds" "set")
117190075Sobrien   (set_attr "type" "mult")]
117290075Sobrien)
117390075Sobrien
117490075Sobrien(define_insn "*mulsi_compare0_scratch"
117590075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
117690075Sobrien	(compare:CC_NOOV (mult:SI
117790075Sobrien			  (match_operand:SI 2 "s_register_operand" "r,r")
117890075Sobrien			  (match_operand:SI 1 "s_register_operand" "%?r,0"))
117990075Sobrien			 (const_int 0)))
118090075Sobrien   (clobber (match_scratch:SI 0 "=&r,&r"))]
1181132718Skan  "TARGET_ARM && !arm_arch_xscale"
118290075Sobrien  "mul%?s\\t%0, %2, %1"
118390075Sobrien  [(set_attr "conds" "set")
118490075Sobrien   (set_attr "type" "mult")]
118590075Sobrien)
118690075Sobrien
118790075Sobrien;; Unnamed templates to match MLA instruction.
118890075Sobrien
118990075Sobrien(define_insn "*mulsi3addsi"
119090075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r,&r")
119190075Sobrien	(plus:SI
119290075Sobrien	  (mult:SI (match_operand:SI 2 "s_register_operand" "r,r,r,r")
119390075Sobrien		   (match_operand:SI 1 "s_register_operand" "%r,0,r,0"))
119490075Sobrien	  (match_operand:SI 3 "s_register_operand" "?r,r,0,0")))]
119590075Sobrien  "TARGET_ARM"
119690075Sobrien  "mla%?\\t%0, %2, %1, %3"
119790075Sobrien  [(set_attr "type" "mult")
119890075Sobrien   (set_attr "predicable" "yes")]
119990075Sobrien)
120090075Sobrien
120190075Sobrien(define_insn "*mulsi3addsi_compare0"
120290075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
120390075Sobrien	(compare:CC_NOOV
120490075Sobrien	 (plus:SI (mult:SI
120590075Sobrien		   (match_operand:SI 2 "s_register_operand" "r,r,r,r")
120690075Sobrien		   (match_operand:SI 1 "s_register_operand" "%r,0,r,0"))
120790075Sobrien		  (match_operand:SI 3 "s_register_operand" "?r,r,0,0"))
120890075Sobrien	 (const_int 0)))
120990075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r,&r")
121090075Sobrien	(plus:SI (mult:SI (match_dup 2) (match_dup 1))
121190075Sobrien		 (match_dup 3)))]
1212132718Skan  "TARGET_ARM && !arm_arch_xscale"
121390075Sobrien  "mla%?s\\t%0, %2, %1, %3"
121490075Sobrien  [(set_attr "conds" "set")
121590075Sobrien   (set_attr "type" "mult")]
121690075Sobrien)
121790075Sobrien
121890075Sobrien(define_insn "*mulsi3addsi_compare0_scratch"
121990075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
122090075Sobrien	(compare:CC_NOOV
122190075Sobrien	 (plus:SI (mult:SI
122290075Sobrien		   (match_operand:SI 2 "s_register_operand" "r,r,r,r")
122390075Sobrien		   (match_operand:SI 1 "s_register_operand" "%r,0,r,0"))
122490075Sobrien		  (match_operand:SI 3 "s_register_operand" "?r,r,0,0"))
122590075Sobrien	 (const_int 0)))
122690075Sobrien   (clobber (match_scratch:SI 0 "=&r,&r,&r,&r"))]
1227132718Skan  "TARGET_ARM && !arm_arch_xscale"
122890075Sobrien  "mla%?s\\t%0, %2, %1, %3"
122990075Sobrien  [(set_attr "conds" "set")
123090075Sobrien   (set_attr "type" "mult")]
123190075Sobrien)
123290075Sobrien
1233132718Skan;; Unnamed template to match long long multiply-accumulate (smlal)
123490075Sobrien
123590075Sobrien(define_insn "*mulsidi3adddi"
123690075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r")
123790075Sobrien	(plus:DI
123890075Sobrien	 (mult:DI
123990075Sobrien	  (sign_extend:DI (match_operand:SI 2 "s_register_operand" "%r"))
124090075Sobrien	  (sign_extend:DI (match_operand:SI 3 "s_register_operand" "r")))
124190075Sobrien	 (match_operand:DI 1 "s_register_operand" "0")))]
124290075Sobrien  "TARGET_ARM && arm_fast_multiply"
124390075Sobrien  "smlal%?\\t%Q0, %R0, %3, %2"
124490075Sobrien  [(set_attr "type" "mult")
124590075Sobrien   (set_attr "predicable" "yes")]
124690075Sobrien)
124790075Sobrien
124890075Sobrien(define_insn "mulsidi3"
124990075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r")
125090075Sobrien	(mult:DI
125190075Sobrien	 (sign_extend:DI (match_operand:SI 1 "s_register_operand" "%r"))
125290075Sobrien	 (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r"))))]
125390075Sobrien  "TARGET_ARM && arm_fast_multiply"
125490075Sobrien  "smull%?\\t%Q0, %R0, %1, %2"
125590075Sobrien  [(set_attr "type" "mult")
125690075Sobrien   (set_attr "predicable" "yes")]
125790075Sobrien)
125890075Sobrien
125990075Sobrien(define_insn "umulsidi3"
126090075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r")
126190075Sobrien	(mult:DI
126290075Sobrien	 (zero_extend:DI (match_operand:SI 1 "s_register_operand" "%r"))
126390075Sobrien	 (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r"))))]
126490075Sobrien  "TARGET_ARM && arm_fast_multiply"
126590075Sobrien  "umull%?\\t%Q0, %R0, %1, %2"
126690075Sobrien  [(set_attr "type" "mult")
126790075Sobrien   (set_attr "predicable" "yes")]
126890075Sobrien)
126990075Sobrien
1270132718Skan;; Unnamed template to match long long unsigned multiply-accumulate (umlal)
127190075Sobrien
127290075Sobrien(define_insn "*umulsidi3adddi"
127390075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r")
127490075Sobrien	(plus:DI
127590075Sobrien	 (mult:DI
127690075Sobrien	  (zero_extend:DI (match_operand:SI 2 "s_register_operand" "%r"))
127790075Sobrien	  (zero_extend:DI (match_operand:SI 3 "s_register_operand" "r")))
127890075Sobrien	 (match_operand:DI 1 "s_register_operand" "0")))]
127990075Sobrien  "TARGET_ARM && arm_fast_multiply"
128090075Sobrien  "umlal%?\\t%Q0, %R0, %3, %2"
128190075Sobrien  [(set_attr "type" "mult")
128290075Sobrien   (set_attr "predicable" "yes")]
128390075Sobrien)
128490075Sobrien
128590075Sobrien(define_insn "smulsi3_highpart"
128690075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=&r,&r")
128790075Sobrien	(truncate:SI
128890075Sobrien	 (lshiftrt:DI
128990075Sobrien	  (mult:DI
129090075Sobrien	   (sign_extend:DI (match_operand:SI 1 "s_register_operand" "%r,0"))
129190075Sobrien	   (sign_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")))
129290075Sobrien	  (const_int 32))))
129390075Sobrien   (clobber (match_scratch:SI 3 "=&r,&r"))]
129490075Sobrien  "TARGET_ARM && arm_fast_multiply"
129590075Sobrien  "smull%?\\t%3, %0, %2, %1"
129690075Sobrien  [(set_attr "type" "mult")
129790075Sobrien   (set_attr "predicable" "yes")]
129890075Sobrien)
129990075Sobrien
130090075Sobrien(define_insn "umulsi3_highpart"
130190075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=&r,&r")
130290075Sobrien	(truncate:SI
130390075Sobrien	 (lshiftrt:DI
130490075Sobrien	  (mult:DI
130590075Sobrien	   (zero_extend:DI (match_operand:SI 1 "s_register_operand" "%r,0"))
130690075Sobrien	   (zero_extend:DI (match_operand:SI 2 "s_register_operand" "r,r")))
130790075Sobrien	  (const_int 32))))
130890075Sobrien   (clobber (match_scratch:SI 3 "=&r,&r"))]
130990075Sobrien  "TARGET_ARM && arm_fast_multiply"
131090075Sobrien  "umull%?\\t%3, %0, %2, %1"
131190075Sobrien  [(set_attr "type" "mult")
131290075Sobrien   (set_attr "predicable" "yes")]
131390075Sobrien)
131490075Sobrien
131590075Sobrien(define_insn "mulhisi3"
131690075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
131790075Sobrien	(mult:SI (sign_extend:SI
131890075Sobrien		  (match_operand:HI 1 "s_register_operand" "%r"))
131990075Sobrien		 (sign_extend:SI
132090075Sobrien		  (match_operand:HI 2 "s_register_operand" "r"))))]
1321132718Skan  "TARGET_ARM && arm_arch5e"
132290075Sobrien  "smulbb%?\\t%0, %1, %2"
1323132718Skan  [(set_attr "type" "mult")
1324132718Skan   (set_attr "predicable" "yes")]
132590075Sobrien)
132690075Sobrien
1327132718Skan(define_insn "*mulhisi3tb"
1328132718Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
1329132718Skan	(mult:SI (ashiftrt:SI
1330132718Skan		  (match_operand:SI 1 "s_register_operand" "r")
1331132718Skan		  (const_int 16))
1332132718Skan		 (sign_extend:SI
1333132718Skan		  (match_operand:HI 2 "s_register_operand" "r"))))]
1334132718Skan  "TARGET_ARM && arm_arch5e"
1335132718Skan  "smultb%?\\t%0, %1, %2"
1336132718Skan  [(set_attr "type" "mult")
1337132718Skan   (set_attr "predicable" "yes")]
1338132718Skan)
1339132718Skan
1340132718Skan(define_insn "*mulhisi3bt"
1341132718Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
1342132718Skan	(mult:SI (sign_extend:SI
1343132718Skan		  (match_operand:HI 1 "s_register_operand" "r"))
1344132718Skan		 (ashiftrt:SI
1345132718Skan		  (match_operand:SI 2 "s_register_operand" "r")
1346132718Skan		  (const_int 16))))]
1347132718Skan  "TARGET_ARM && arm_arch5e"
1348132718Skan  "smulbt%?\\t%0, %1, %2"
1349132718Skan  [(set_attr "type" "mult")
1350132718Skan   (set_attr "predicable" "yes")]
1351132718Skan)
1352132718Skan
1353132718Skan(define_insn "*mulhisi3tt"
1354132718Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
1355132718Skan	(mult:SI (ashiftrt:SI
1356132718Skan		  (match_operand:SI 1 "s_register_operand" "r")
1357132718Skan		  (const_int 16))
1358132718Skan		 (ashiftrt:SI
1359132718Skan		  (match_operand:SI 2 "s_register_operand" "r")
1360132718Skan		  (const_int 16))))]
1361132718Skan  "TARGET_ARM && arm_arch5e"
1362132718Skan  "smultt%?\\t%0, %1, %2"
1363132718Skan  [(set_attr "type" "mult")
1364132718Skan   (set_attr "predicable" "yes")]
1365132718Skan)
1366132718Skan
136790075Sobrien(define_insn "*mulhisi3addsi"
136890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
136990075Sobrien	(plus:SI (match_operand:SI 1 "s_register_operand" "r")
137090075Sobrien		 (mult:SI (sign_extend:SI
137190075Sobrien			   (match_operand:HI 2 "s_register_operand" "%r"))
137290075Sobrien			  (sign_extend:SI
137390075Sobrien			   (match_operand:HI 3 "s_register_operand" "r")))))]
1374132718Skan  "TARGET_ARM && arm_arch5e"
137590075Sobrien  "smlabb%?\\t%0, %2, %3, %1"
1376132718Skan  [(set_attr "type" "mult")
1377132718Skan   (set_attr "predicable" "yes")]
137890075Sobrien)
137990075Sobrien
138090075Sobrien(define_insn "*mulhidi3adddi"
138190075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=r")
138290075Sobrien	(plus:DI
138390075Sobrien	  (match_operand:DI 1 "s_register_operand" "0")
138490075Sobrien	  (mult:DI (sign_extend:DI
138590075Sobrien	 	    (match_operand:HI 2 "s_register_operand" "%r"))
138690075Sobrien		   (sign_extend:DI
138790075Sobrien		    (match_operand:HI 3 "s_register_operand" "r")))))]
1388132718Skan  "TARGET_ARM && arm_arch5e"
138990075Sobrien  "smlalbb%?\\t%Q0, %R0, %2, %3"
1390132718Skan  [(set_attr "type" "mult")
1391132718Skan   (set_attr "predicable" "yes")])
139290075Sobrien
1393132718Skan(define_expand "mulsf3"
1394132718Skan  [(set (match_operand:SF          0 "s_register_operand" "")
1395132718Skan	(mult:SF (match_operand:SF 1 "s_register_operand" "")
1396132718Skan		 (match_operand:SF 2 "fpa_rhs_operand" "")))]
1397132718Skan  "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
1398132718Skan  "
1399132718Skan  if (TARGET_CIRRUS
1400132718Skan      && !cirrus_fp_register (operands[2], SFmode))
1401132718Skan    operands[2] = force_reg (SFmode, operands[2]);
1402132718Skan")
140390075Sobrien
1404132718Skan(define_expand "muldf3"
1405132718Skan  [(set (match_operand:DF          0 "s_register_operand" "")
1406132718Skan	(mult:DF (match_operand:DF 1 "s_register_operand" "")
1407132718Skan		 (match_operand:DF 2 "fpa_rhs_operand" "")))]
1408132718Skan  "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
1409132718Skan  "
1410132718Skan  if (TARGET_CIRRUS
1411132718Skan      && !cirrus_fp_register (operands[2], DFmode))
1412132718Skan    operands[2] = force_reg (DFmode, operands[2]);
1413132718Skan")
141490075Sobrien
141590075Sobrien;; Division insns
141690075Sobrien
1417132718Skan(define_expand "divsf3"
1418132718Skan  [(set (match_operand:SF 0 "s_register_operand" "")
1419132718Skan	(div:SF (match_operand:SF 1 "fpa_rhs_operand" "")
1420132718Skan		(match_operand:SF 2 "fpa_rhs_operand" "")))]
142190075Sobrien  "TARGET_ARM && TARGET_HARD_FLOAT"
1422132718Skan  "")
142390075Sobrien
1424132718Skan(define_expand "divdf3"
1425132718Skan  [(set (match_operand:DF 0 "s_register_operand" "")
1426132718Skan	(div:DF (match_operand:DF 1 "fpa_rhs_operand" "")
1427132718Skan		(match_operand:DF 2 "fpa_rhs_operand" "")))]
142890075Sobrien  "TARGET_ARM && TARGET_HARD_FLOAT"
1429132718Skan  "")
143090075Sobrien
143190075Sobrien;; Modulo insns
143290075Sobrien
1433132718Skan(define_expand "modsf3"
1434132718Skan  [(set (match_operand:SF 0 "s_register_operand" "")
1435132718Skan	(mod:SF (match_operand:SF 1 "s_register_operand" "")
1436132718Skan		(match_operand:SF 2 "fpa_rhs_operand" "")))]
143790075Sobrien  "TARGET_ARM && TARGET_HARD_FLOAT"
1438132718Skan  "")
143990075Sobrien
1440132718Skan(define_expand "moddf3"
1441132718Skan  [(set (match_operand:DF 0 "s_register_operand" "")
1442132718Skan	(mod:DF (match_operand:DF 1 "s_register_operand" "")
1443132718Skan		(match_operand:DF 2 "fpa_rhs_operand" "")))]
144490075Sobrien  "TARGET_ARM && TARGET_HARD_FLOAT"
1445132718Skan  "")
144690075Sobrien
144790075Sobrien;; Boolean and,ior,xor insns
144890075Sobrien
144990075Sobrien;; Split up double word logical operations
145090075Sobrien
145190075Sobrien;; Split up simple DImode logical operations.  Simply perform the logical
145290075Sobrien;; operation on the upper and lower halves of the registers.
145390075Sobrien(define_split
145490075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "")
145590075Sobrien	(match_operator:DI 6 "logical_binary_operator"
145690075Sobrien	  [(match_operand:DI 1 "s_register_operand" "")
145790075Sobrien	   (match_operand:DI 2 "s_register_operand" "")]))]
1458132718Skan  "TARGET_ARM && reload_completed && ! IS_IWMMXT_REGNUM (REGNO (operands[0]))"
145990075Sobrien  [(set (match_dup 0) (match_op_dup:SI 6 [(match_dup 1) (match_dup 2)]))
146090075Sobrien   (set (match_dup 3) (match_op_dup:SI 6 [(match_dup 4) (match_dup 5)]))]
146190075Sobrien  "
146290075Sobrien  {
146390075Sobrien    operands[3] = gen_highpart (SImode, operands[0]);
146490075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
146590075Sobrien    operands[4] = gen_highpart (SImode, operands[1]);
146690075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
146790075Sobrien    operands[5] = gen_highpart (SImode, operands[2]);
146890075Sobrien    operands[2] = gen_lowpart (SImode, operands[2]);
146990075Sobrien  }"
147090075Sobrien)
147190075Sobrien
147290075Sobrien(define_split
147390075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "")
147490075Sobrien	(match_operator:DI 6 "logical_binary_operator"
147590075Sobrien	  [(sign_extend:DI (match_operand:SI 2 "s_register_operand" ""))
147690075Sobrien	   (match_operand:DI 1 "s_register_operand" "")]))]
147790075Sobrien  "TARGET_ARM && reload_completed"
147890075Sobrien  [(set (match_dup 0) (match_op_dup:SI 6 [(match_dup 1) (match_dup 2)]))
147990075Sobrien   (set (match_dup 3) (match_op_dup:SI 6
148090075Sobrien			[(ashiftrt:SI (match_dup 2) (const_int 31))
148190075Sobrien			 (match_dup 4)]))]
148290075Sobrien  "
148390075Sobrien  {
148490075Sobrien    operands[3] = gen_highpart (SImode, operands[0]);
148590075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
148690075Sobrien    operands[4] = gen_highpart (SImode, operands[1]);
148790075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
148890075Sobrien    operands[5] = gen_highpart (SImode, operands[2]);
148990075Sobrien    operands[2] = gen_lowpart (SImode, operands[2]);
149090075Sobrien  }"
149190075Sobrien)
149290075Sobrien
149390075Sobrien;; The zero extend of operand 2 means we can just copy the high part of
149490075Sobrien;; operand1 into operand0.
149590075Sobrien(define_split
149690075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "")
149790075Sobrien	(ior:DI
149890075Sobrien	  (zero_extend:DI (match_operand:SI 2 "s_register_operand" ""))
149990075Sobrien	  (match_operand:DI 1 "s_register_operand" "")))]
150090075Sobrien  "TARGET_ARM && operands[0] != operands[1] && reload_completed"
150190075Sobrien  [(set (match_dup 0) (ior:SI (match_dup 1) (match_dup 2)))
150290075Sobrien   (set (match_dup 3) (match_dup 4))]
150390075Sobrien  "
150490075Sobrien  {
150590075Sobrien    operands[4] = gen_highpart (SImode, operands[1]);
150690075Sobrien    operands[3] = gen_highpart (SImode, operands[0]);
150790075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
150890075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
150990075Sobrien  }"
151090075Sobrien)
151190075Sobrien
151290075Sobrien;; The zero extend of operand 2 means we can just copy the high part of
151390075Sobrien;; operand1 into operand0.
151490075Sobrien(define_split
151590075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "")
151690075Sobrien	(xor:DI
151790075Sobrien	  (zero_extend:DI (match_operand:SI 2 "s_register_operand" ""))
151890075Sobrien	  (match_operand:DI 1 "s_register_operand" "")))]
151990075Sobrien  "TARGET_ARM && operands[0] != operands[1] && reload_completed"
152090075Sobrien  [(set (match_dup 0) (xor:SI (match_dup 1) (match_dup 2)))
152190075Sobrien   (set (match_dup 3) (match_dup 4))]
152290075Sobrien  "
152390075Sobrien  {
152490075Sobrien    operands[4] = gen_highpart (SImode, operands[1]);
152590075Sobrien    operands[3] = gen_highpart (SImode, operands[0]);
152690075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
152790075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
152890075Sobrien  }"
152990075Sobrien)
153090075Sobrien
153190075Sobrien(define_insn "anddi3"
153290075Sobrien  [(set (match_operand:DI         0 "s_register_operand" "=&r,&r")
153390075Sobrien	(and:DI (match_operand:DI 1 "s_register_operand"  "%0,r")
153490075Sobrien		(match_operand:DI 2 "s_register_operand"   "r,r")))]
1535132718Skan  "TARGET_ARM && ! TARGET_IWMMXT"
153690075Sobrien  "#"
153790075Sobrien  [(set_attr "length" "8")]
153890075Sobrien)
153990075Sobrien
154090075Sobrien(define_insn_and_split "*anddi_zesidi_di"
154190075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
154290075Sobrien	(and:DI (zero_extend:DI
154390075Sobrien		 (match_operand:SI 2 "s_register_operand" "r,r"))
154490075Sobrien		(match_operand:DI 1 "s_register_operand" "?r,0")))]
154590075Sobrien  "TARGET_ARM"
154690075Sobrien  "#"
154790075Sobrien  "TARGET_ARM && reload_completed"
154890075Sobrien  ; The zero extend of operand 2 clears the high word of the output
154990075Sobrien  ; operand.
155090075Sobrien  [(set (match_dup 0) (and:SI (match_dup 1) (match_dup 2)))
155190075Sobrien   (set (match_dup 3) (const_int 0))]
155290075Sobrien  "
155390075Sobrien  {
155490075Sobrien    operands[3] = gen_highpart (SImode, operands[0]);
155590075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
155690075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
155790075Sobrien  }"
155890075Sobrien  [(set_attr "length" "8")]
155990075Sobrien)
156090075Sobrien
156190075Sobrien(define_insn "*anddi_sesdi_di"
156290075Sobrien  [(set (match_operand:DI          0 "s_register_operand" "=&r,&r")
156390075Sobrien	(and:DI (sign_extend:DI
156490075Sobrien		 (match_operand:SI 2 "s_register_operand" "r,r"))
156590075Sobrien		(match_operand:DI  1 "s_register_operand" "?r,0")))]
156690075Sobrien  "TARGET_ARM"
156790075Sobrien  "#"
156890075Sobrien  [(set_attr "length" "8")]
156990075Sobrien)
157090075Sobrien
157190075Sobrien(define_expand "andsi3"
157290075Sobrien  [(set (match_operand:SI         0 "s_register_operand" "")
157390075Sobrien	(and:SI (match_operand:SI 1 "s_register_operand" "")
157490075Sobrien		(match_operand:SI 2 "reg_or_int_operand" "")))]
157590075Sobrien  "TARGET_EITHER"
157690075Sobrien  "
157790075Sobrien  if (TARGET_ARM)
157890075Sobrien    {
157990075Sobrien      if (GET_CODE (operands[2]) == CONST_INT)
158090075Sobrien        {
158190075Sobrien          arm_split_constant (AND, SImode, INTVAL (operands[2]), operands[0],
158290075Sobrien			      operands[1],
158390075Sobrien			      (no_new_pseudos
158490075Sobrien			       ? 0 : preserve_subexpressions_p ()));
158590075Sobrien          DONE;
158690075Sobrien        }
158790075Sobrien    }
158890075Sobrien  else /* TARGET_THUMB */
158990075Sobrien    {
159090075Sobrien      if (GET_CODE (operands[2]) != CONST_INT)
159190075Sobrien        operands[2] = force_reg (SImode, operands[2]);
159290075Sobrien      else
159390075Sobrien        {
159490075Sobrien          int i;
159590075Sobrien	  
159690075Sobrien          if (((unsigned HOST_WIDE_INT) ~INTVAL (operands[2])) < 256)
159790075Sobrien  	    {
159890075Sobrien	      operands[2] = force_reg (SImode,
159990075Sobrien				       GEN_INT (~INTVAL (operands[2])));
160090075Sobrien	      
160190075Sobrien	      emit_insn (gen_bicsi3 (operands[0], operands[2], operands[1]));
160290075Sobrien	      
160390075Sobrien	      DONE;
160490075Sobrien	    }
160590075Sobrien
160690075Sobrien          for (i = 9; i <= 31; i++)
160790075Sobrien	    {
160890075Sobrien	      if ((((HOST_WIDE_INT) 1) << i) - 1 == INTVAL (operands[2]))
160990075Sobrien	        {
161090075Sobrien	          emit_insn (gen_extzv (operands[0], operands[1], GEN_INT (i),
161190075Sobrien			 	        const0_rtx));
161290075Sobrien	          DONE;
161390075Sobrien	        }
161490075Sobrien	      else if ((((HOST_WIDE_INT) 1) << i) - 1
161590075Sobrien		       == ~INTVAL (operands[2]))
161690075Sobrien	        {
161790075Sobrien	          rtx shift = GEN_INT (i);
161890075Sobrien	          rtx reg = gen_reg_rtx (SImode);
161990075Sobrien		
162090075Sobrien	          emit_insn (gen_lshrsi3 (reg, operands[1], shift));
162190075Sobrien	          emit_insn (gen_ashlsi3 (operands[0], reg, shift));
162290075Sobrien		  
162390075Sobrien	          DONE;
162490075Sobrien	        }
162590075Sobrien	    }
162690075Sobrien
162790075Sobrien          operands[2] = force_reg (SImode, operands[2]);
162890075Sobrien        }
162990075Sobrien    }
163090075Sobrien  "
163190075Sobrien)
163290075Sobrien
163390075Sobrien(define_insn_and_split "*arm_andsi3_insn"
163490075Sobrien  [(set (match_operand:SI         0 "s_register_operand" "=r,r,r")
163590075Sobrien	(and:SI (match_operand:SI 1 "s_register_operand" "r,r,r")
163690075Sobrien		(match_operand:SI 2 "reg_or_int_operand" "rI,K,?n")))]
163790075Sobrien  "TARGET_ARM"
163890075Sobrien  "@
163990075Sobrien   and%?\\t%0, %1, %2
164090075Sobrien   bic%?\\t%0, %1, #%B2
164190075Sobrien   #"
164290075Sobrien  "TARGET_ARM
164390075Sobrien   && GET_CODE (operands[2]) == CONST_INT
164490075Sobrien   && !(const_ok_for_arm (INTVAL (operands[2]))
164590075Sobrien	|| const_ok_for_arm (~INTVAL (operands[2])))"
164690075Sobrien  [(clobber (const_int 0))]
164790075Sobrien  "
164890075Sobrien  arm_split_constant  (AND, SImode, INTVAL (operands[2]), operands[0],
164990075Sobrien		       operands[1], 0);
165090075Sobrien  DONE;
165190075Sobrien  "
165290075Sobrien  [(set_attr "length" "4,4,16")
165390075Sobrien   (set_attr "predicable" "yes")]
165490075Sobrien)
165590075Sobrien
165690075Sobrien(define_insn "*thumb_andsi3_insn"
165790075Sobrien  [(set (match_operand:SI         0 "register_operand" "=l")
165890075Sobrien	(and:SI (match_operand:SI 1 "register_operand" "%0")
165990075Sobrien		(match_operand:SI 2 "register_operand" "l")))]
166090075Sobrien  "TARGET_THUMB"
166190075Sobrien  "and\\t%0, %0, %2"
166290075Sobrien  [(set_attr "length" "2")]
166390075Sobrien)
166490075Sobrien
166590075Sobrien(define_insn "*andsi3_compare0"
166690075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
166790075Sobrien	(compare:CC_NOOV
166890075Sobrien	 (and:SI (match_operand:SI 1 "s_register_operand" "r,r")
166990075Sobrien		 (match_operand:SI 2 "arm_not_operand" "rI,K"))
167090075Sobrien	 (const_int 0)))
167190075Sobrien   (set (match_operand:SI          0 "s_register_operand" "=r,r")
167290075Sobrien	(and:SI (match_dup 1) (match_dup 2)))]
167390075Sobrien  "TARGET_ARM"
167490075Sobrien  "@
167590075Sobrien   and%?s\\t%0, %1, %2
167690075Sobrien   bic%?s\\t%0, %1, #%B2"
167790075Sobrien  [(set_attr "conds" "set")]
167890075Sobrien)
167990075Sobrien
168090075Sobrien(define_insn "*andsi3_compare0_scratch"
168190075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
168290075Sobrien	(compare:CC_NOOV
168390075Sobrien	 (and:SI (match_operand:SI 0 "s_register_operand" "r,r")
168490075Sobrien		 (match_operand:SI 1 "arm_not_operand" "rI,K"))
168590075Sobrien	 (const_int 0)))
168690075Sobrien   (clobber (match_scratch:SI 2 "=X,r"))]
168790075Sobrien  "TARGET_ARM"
168890075Sobrien  "@
168990075Sobrien   tst%?\\t%0, %1
169090075Sobrien   bic%?s\\t%2, %0, #%B1"
169190075Sobrien  [(set_attr "conds" "set")]
169290075Sobrien)
169390075Sobrien
169490075Sobrien(define_insn "*zeroextractsi_compare0_scratch"
169590075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
169690075Sobrien	(compare:CC_NOOV (zero_extract:SI
169790075Sobrien			  (match_operand:SI 0 "s_register_operand" "r")
169890075Sobrien		 	  (match_operand 1 "const_int_operand" "n")
169990075Sobrien			  (match_operand 2 "const_int_operand" "n"))
170090075Sobrien			 (const_int 0)))]
170190075Sobrien  "TARGET_ARM
170290075Sobrien  && (INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) < 32
170390075Sobrien      && INTVAL (operands[1]) > 0 
170490075Sobrien      && INTVAL (operands[1]) + (INTVAL (operands[2]) & 1) <= 8
170590075Sobrien      && INTVAL (operands[1]) + INTVAL (operands[2]) <= 32)"
170690075Sobrien  "*
170790075Sobrien  operands[1] = GEN_INT (((1 << INTVAL (operands[1])) - 1)
170890075Sobrien			 << INTVAL (operands[2]));
170990075Sobrien  output_asm_insn (\"tst%?\\t%0, %1\", operands);
171090075Sobrien  return \"\";
171190075Sobrien  "
171290075Sobrien  [(set_attr "conds" "set")]
171390075Sobrien)
171490075Sobrien
171590075Sobrien(define_insn "*ne_zeroextractsi"
171690075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
171790075Sobrien	(ne:SI (zero_extract:SI
171890075Sobrien		(match_operand:SI 1 "s_register_operand" "r")
171990075Sobrien		(match_operand:SI 2 "const_int_operand" "n")
172090075Sobrien		(match_operand:SI 3 "const_int_operand" "n"))
1721104752Skan	       (const_int 0)))
1722104752Skan   (clobber (reg:CC CC_REGNUM))]
172390075Sobrien  "TARGET_ARM
172490075Sobrien   && (INTVAL (operands[3]) >= 0 && INTVAL (operands[3]) < 32
172590075Sobrien       && INTVAL (operands[2]) > 0 
172690075Sobrien       && INTVAL (operands[2]) + (INTVAL (operands[3]) & 1) <= 8
172790075Sobrien       && INTVAL (operands[2]) + INTVAL (operands[3]) <= 32)"
172890075Sobrien  "*
172990075Sobrien  operands[2] = GEN_INT (((1 << INTVAL (operands[2])) - 1)
173090075Sobrien			 << INTVAL (operands[3]));
173190075Sobrien  output_asm_insn (\"ands\\t%0, %1, %2\", operands);
173290075Sobrien  return \"movne\\t%0, #1\";
173390075Sobrien  "
173490075Sobrien  [(set_attr "conds" "clob")
173590075Sobrien   (set_attr "length" "8")]
173690075Sobrien)
173790075Sobrien
1738132718Skan(define_split
1739132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
1740132718Skan	(zero_extract:SI (match_operand:SI 1 "s_register_operand" "")
1741132718Skan			 (match_operand:SI 2 "const_int_operand" "")
1742132718Skan			 (match_operand:SI 3 "const_int_operand" "")))
1743132718Skan   (clobber (match_operand:SI 4 "s_register_operand" ""))]
1744132718Skan  "TARGET_THUMB"
1745132718Skan  [(set (match_dup 4) (ashift:SI (match_dup 1) (match_dup 2)))
1746132718Skan   (set (match_dup 0) (lshiftrt:SI (match_dup 4) (match_dup 3)))]
1747132718Skan  "{
1748132718Skan     HOST_WIDE_INT temp = INTVAL (operands[2]);
1749132718Skan
1750132718Skan     operands[2] = GEN_INT (32 - temp - INTVAL (operands[3]));
1751132718Skan     operands[3] = GEN_INT (32 - temp);
1752132718Skan   }"
1753132718Skan)
1754132718Skan
1755132718Skan(define_split
1756132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
1757132718Skan	(match_operator:SI 1 "shiftable_operator"
1758132718Skan	 [(zero_extract:SI (match_operand:SI 2 "s_register_operand" "")
1759132718Skan			   (match_operand:SI 3 "const_int_operand" "")
1760132718Skan			   (match_operand:SI 4 "const_int_operand" ""))
1761132718Skan	  (match_operand:SI 5 "s_register_operand" "")]))
1762132718Skan   (clobber (match_operand:SI 6 "s_register_operand" ""))]
1763132718Skan  "TARGET_ARM"
1764132718Skan  [(set (match_dup 6) (ashift:SI (match_dup 2) (match_dup 3)))
1765132718Skan   (set (match_dup 0)
1766132718Skan	(match_op_dup 1
1767132718Skan	 [(lshiftrt:SI (match_dup 6) (match_dup 4))
1768132718Skan	  (match_dup 5)]))]
1769132718Skan  "{
1770132718Skan     HOST_WIDE_INT temp = INTVAL (operands[3]);
1771132718Skan
1772132718Skan     operands[3] = GEN_INT (32 - temp - INTVAL (operands[4]));
1773132718Skan     operands[4] = GEN_INT (32 - temp);
1774132718Skan   }"
1775132718Skan)
1776132718Skan  
1777132718Skan(define_split
1778132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
1779132718Skan	(sign_extract:SI (match_operand:SI 1 "s_register_operand" "")
1780132718Skan			 (match_operand:SI 2 "const_int_operand" "")
1781132718Skan			 (match_operand:SI 3 "const_int_operand" "")))]
1782132718Skan  "TARGET_THUMB"
1783132718Skan  [(set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))
1784132718Skan   (set (match_dup 0) (ashiftrt:SI (match_dup 0) (match_dup 3)))]
1785132718Skan  "{
1786132718Skan     HOST_WIDE_INT temp = INTVAL (operands[2]);
1787132718Skan
1788132718Skan     operands[2] = GEN_INT (32 - temp - INTVAL (operands[3]));
1789132718Skan     operands[3] = GEN_INT (32 - temp);
1790132718Skan   }"
1791132718Skan)
1792132718Skan
1793132718Skan(define_split
1794132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
1795132718Skan	(match_operator:SI 1 "shiftable_operator"
1796132718Skan	 [(sign_extract:SI (match_operand:SI 2 "s_register_operand" "")
1797132718Skan			   (match_operand:SI 3 "const_int_operand" "")
1798132718Skan			   (match_operand:SI 4 "const_int_operand" ""))
1799132718Skan	  (match_operand:SI 5 "s_register_operand" "")]))
1800132718Skan   (clobber (match_operand:SI 6 "s_register_operand" ""))]
1801132718Skan  "TARGET_ARM"
1802132718Skan  [(set (match_dup 6) (ashift:SI (match_dup 2) (match_dup 3)))
1803132718Skan   (set (match_dup 0)
1804132718Skan	(match_op_dup 1
1805132718Skan	 [(ashiftrt:SI (match_dup 6) (match_dup 4))
1806132718Skan	  (match_dup 5)]))]
1807132718Skan  "{
1808132718Skan     HOST_WIDE_INT temp = INTVAL (operands[3]);
1809132718Skan
1810132718Skan     operands[3] = GEN_INT (32 - temp - INTVAL (operands[4]));
1811132718Skan     operands[4] = GEN_INT (32 - temp);
1812132718Skan   }"
1813132718Skan)
1814132718Skan  
181590075Sobrien;;; ??? This pattern is bogus.  If operand3 has bits outside the range
181690075Sobrien;;; represented by the bitfield, then this will produce incorrect results.
181790075Sobrien;;; Somewhere, the value needs to be truncated.  On targets like the m68k,
1818117395Skan;;; which have a real bit-field insert instruction, the truncation happens
1819117395Skan;;; in the bit-field insert instruction itself.  Since arm does not have a
1820117395Skan;;; bit-field insert instruction, we would have to emit code here to truncate
182190075Sobrien;;; the value before we insert.  This loses some of the advantage of having
182290075Sobrien;;; this insv pattern, so this pattern needs to be reevalutated.
182390075Sobrien
182490075Sobrien(define_expand "insv"
182590075Sobrien  [(set (zero_extract:SI (match_operand:SI 0 "s_register_operand" "")
182690075Sobrien                         (match_operand:SI 1 "general_operand" "")
182790075Sobrien                         (match_operand:SI 2 "general_operand" ""))
1828117395Skan        (match_operand:SI 3 "reg_or_int_operand" ""))]
182990075Sobrien  "TARGET_ARM"
183090075Sobrien  "
183190075Sobrien  {
183290075Sobrien    int start_bit = INTVAL (operands[2]);
183390075Sobrien    int width = INTVAL (operands[1]);
183490075Sobrien    HOST_WIDE_INT mask = (((HOST_WIDE_INT)1) << width) - 1;
183590075Sobrien    rtx target, subtarget;
183690075Sobrien
183790075Sobrien    target = operands[0];
183890075Sobrien    /* Avoid using a subreg as a subtarget, and avoid writing a paradoxical 
183990075Sobrien       subreg as the final target.  */
184090075Sobrien    if (GET_CODE (target) == SUBREG)
184190075Sobrien      {
184290075Sobrien	subtarget = gen_reg_rtx (SImode);
184390075Sobrien	if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (target)))
184490075Sobrien	    < GET_MODE_SIZE (SImode))
184590075Sobrien	  target = SUBREG_REG (target);
184690075Sobrien      }
184790075Sobrien    else
184890075Sobrien      subtarget = target;    
184990075Sobrien
185090075Sobrien    if (GET_CODE (operands[3]) == CONST_INT)
185190075Sobrien      {
185290075Sobrien	/* Since we are inserting a known constant, we may be able to
185390075Sobrien	   reduce the number of bits that we have to clear so that
185490075Sobrien	   the mask becomes simple.  */
185590075Sobrien	/* ??? This code does not check to see if the new mask is actually
185690075Sobrien	   simpler.  It may not be.  */
185790075Sobrien	rtx op1 = gen_reg_rtx (SImode);
185890075Sobrien	/* ??? Truncate operand3 to fit in the bitfield.  See comment before
185990075Sobrien	   start of this pattern.  */
186090075Sobrien	HOST_WIDE_INT op3_value = mask & INTVAL (operands[3]);
186190075Sobrien	HOST_WIDE_INT mask2 = ((mask & ~op3_value) << start_bit);
186290075Sobrien
186390075Sobrien	emit_insn (gen_andsi3 (op1, operands[0], GEN_INT (~mask2)));
186490075Sobrien	emit_insn (gen_iorsi3 (subtarget, op1,
186590075Sobrien			       GEN_INT (op3_value << start_bit)));
186690075Sobrien      }
186790075Sobrien    else if (start_bit == 0
186890075Sobrien	     && !(const_ok_for_arm (mask)
186990075Sobrien		  || const_ok_for_arm (~mask)))
187090075Sobrien      {
187190075Sobrien	/* A Trick, since we are setting the bottom bits in the word,
187290075Sobrien	   we can shift operand[3] up, operand[0] down, OR them together
187390075Sobrien	   and rotate the result back again.  This takes 3 insns, and
1874132718Skan	   the third might be mergeable into another op.  */
187590075Sobrien	/* The shift up copes with the possibility that operand[3] is
187690075Sobrien           wider than the bitfield.  */
187790075Sobrien	rtx op0 = gen_reg_rtx (SImode);
187890075Sobrien	rtx op1 = gen_reg_rtx (SImode);
187990075Sobrien
188090075Sobrien	emit_insn (gen_ashlsi3 (op0, operands[3], GEN_INT (32 - width)));
188190075Sobrien	emit_insn (gen_lshrsi3 (op1, operands[0], operands[1]));
188290075Sobrien	emit_insn (gen_iorsi3  (op1, op1, op0));
188390075Sobrien	emit_insn (gen_rotlsi3 (subtarget, op1, operands[1]));
188490075Sobrien      }
188590075Sobrien    else if ((width + start_bit == 32)
188690075Sobrien	     && !(const_ok_for_arm (mask)
188790075Sobrien		  || const_ok_for_arm (~mask)))
188890075Sobrien      {
188990075Sobrien	/* Similar trick, but slightly less efficient.  */
189090075Sobrien
189190075Sobrien	rtx op0 = gen_reg_rtx (SImode);
189290075Sobrien	rtx op1 = gen_reg_rtx (SImode);
189390075Sobrien
189490075Sobrien	emit_insn (gen_ashlsi3 (op0, operands[3], GEN_INT (32 - width)));
189590075Sobrien	emit_insn (gen_ashlsi3 (op1, operands[0], operands[1]));
189690075Sobrien	emit_insn (gen_lshrsi3 (op1, op1, operands[1]));
189790075Sobrien	emit_insn (gen_iorsi3 (subtarget, op1, op0));
189890075Sobrien      }
189990075Sobrien    else
190090075Sobrien      {
190190075Sobrien	rtx op0 = GEN_INT (mask);
190290075Sobrien	rtx op1 = gen_reg_rtx (SImode);
190390075Sobrien	rtx op2 = gen_reg_rtx (SImode);
190490075Sobrien
190590075Sobrien	if (!(const_ok_for_arm (mask) || const_ok_for_arm (~mask)))
190690075Sobrien	  {
190790075Sobrien	    rtx tmp = gen_reg_rtx (SImode);
190890075Sobrien
190990075Sobrien	    emit_insn (gen_movsi (tmp, op0));
191090075Sobrien	    op0 = tmp;
191190075Sobrien	  }
191290075Sobrien
191390075Sobrien	/* Mask out any bits in operand[3] that are not needed.  */
191490075Sobrien	   emit_insn (gen_andsi3 (op1, operands[3], op0));
191590075Sobrien
191690075Sobrien	if (GET_CODE (op0) == CONST_INT
191790075Sobrien	    && (const_ok_for_arm (mask << start_bit)
191890075Sobrien		|| const_ok_for_arm (~(mask << start_bit))))
191990075Sobrien	  {
192090075Sobrien	    op0 = GEN_INT (~(mask << start_bit));
192190075Sobrien	    emit_insn (gen_andsi3 (op2, operands[0], op0));
192290075Sobrien	  }
192390075Sobrien	else
192490075Sobrien	  {
192590075Sobrien	    if (GET_CODE (op0) == CONST_INT)
192690075Sobrien	      {
192790075Sobrien		rtx tmp = gen_reg_rtx (SImode);
192890075Sobrien
192990075Sobrien		emit_insn (gen_movsi (tmp, op0));
193090075Sobrien		op0 = tmp;
193190075Sobrien	      }
193290075Sobrien
193390075Sobrien	    if (start_bit != 0)
193490075Sobrien	      emit_insn (gen_ashlsi3 (op0, op0, operands[2]));
193590075Sobrien	    
193690075Sobrien	    emit_insn (gen_andsi_notsi_si (op2, operands[0], op0));
193790075Sobrien	  }
193890075Sobrien
193990075Sobrien	if (start_bit != 0)
194090075Sobrien          emit_insn (gen_ashlsi3 (op1, op1, operands[2]));
194190075Sobrien
194290075Sobrien	emit_insn (gen_iorsi3 (subtarget, op1, op2));
194390075Sobrien      }
194490075Sobrien
194590075Sobrien    if (subtarget != target)
194690075Sobrien      {
194790075Sobrien	/* If TARGET is still a SUBREG, then it must be wider than a word,
194890075Sobrien	   so we must be careful only to set the subword we were asked to.  */
194990075Sobrien	if (GET_CODE (target) == SUBREG)
195090075Sobrien	  emit_move_insn (target, subtarget);
195190075Sobrien	else
195290075Sobrien	  emit_move_insn (target, gen_lowpart (GET_MODE (target), subtarget));
195390075Sobrien      }
195490075Sobrien
195590075Sobrien    DONE;
195690075Sobrien  }"
195790075Sobrien)
195890075Sobrien
195990075Sobrien; constants for op 2 will never be given to these patterns.
196090075Sobrien(define_insn_and_split "*anddi_notdi_di"
196190075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
196290075Sobrien	(and:DI (not:DI (match_operand:DI 1 "s_register_operand" "r,0"))
196390075Sobrien		(match_operand:DI 2 "s_register_operand" "0,r")))]
196490075Sobrien  "TARGET_ARM"
196590075Sobrien  "#"
1966132718Skan  "TARGET_ARM && reload_completed && ! IS_IWMMXT_REGNUM (REGNO (operands[0]))"
196790075Sobrien  [(set (match_dup 0) (and:SI (not:SI (match_dup 1)) (match_dup 2)))
196890075Sobrien   (set (match_dup 3) (and:SI (not:SI (match_dup 4)) (match_dup 5)))]
196990075Sobrien  "
197090075Sobrien  {
197190075Sobrien    operands[3] = gen_highpart (SImode, operands[0]);
197290075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
197390075Sobrien    operands[4] = gen_highpart (SImode, operands[1]);
197490075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
197590075Sobrien    operands[5] = gen_highpart (SImode, operands[2]);
197690075Sobrien    operands[2] = gen_lowpart (SImode, operands[2]);
197790075Sobrien  }"
197890075Sobrien  [(set_attr "length" "8")
197990075Sobrien   (set_attr "predicable" "yes")]
198090075Sobrien)
198190075Sobrien  
198290075Sobrien(define_insn_and_split "*anddi_notzesidi_di"
198390075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
198490075Sobrien	(and:DI (not:DI (zero_extend:DI
198590075Sobrien			 (match_operand:SI 2 "s_register_operand" "r,r")))
198690075Sobrien		(match_operand:DI 1 "s_register_operand" "0,?r")))]
198790075Sobrien  "TARGET_ARM"
198890075Sobrien  "@
198990075Sobrien   bic%?\\t%Q0, %Q1, %2
199090075Sobrien   #"
199190075Sobrien  ; (not (zero_extend ...)) allows us to just copy the high word from
199290075Sobrien  ; operand1 to operand0.
199390075Sobrien  "TARGET_ARM
199490075Sobrien   && reload_completed
199590075Sobrien   && operands[0] != operands[1]"
1996117395Skan  [(set (match_dup 0) (and:SI (not:SI (match_dup 2)) (match_dup 1)))
199790075Sobrien   (set (match_dup 3) (match_dup 4))]
199890075Sobrien  "
199990075Sobrien  {
200090075Sobrien    operands[3] = gen_highpart (SImode, operands[0]);
200190075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
200290075Sobrien    operands[4] = gen_highpart (SImode, operands[1]);
200390075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
200490075Sobrien  }"
200590075Sobrien  [(set_attr "length" "4,8")
200690075Sobrien   (set_attr "predicable" "yes")]
200790075Sobrien)
200890075Sobrien  
200990075Sobrien(define_insn_and_split "*anddi_notsesidi_di"
201090075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
201190075Sobrien	(and:DI (not:DI (sign_extend:DI
201290075Sobrien			 (match_operand:SI 2 "s_register_operand" "r,r")))
2013117395Skan		(match_operand:DI 1 "s_register_operand" "0,r")))]
201490075Sobrien  "TARGET_ARM"
201590075Sobrien  "#"
201690075Sobrien  "TARGET_ARM && reload_completed"
2017117395Skan  [(set (match_dup 0) (and:SI (not:SI (match_dup 2)) (match_dup 1)))
201890075Sobrien   (set (match_dup 3) (and:SI (not:SI
201990075Sobrien				(ashiftrt:SI (match_dup 2) (const_int 31)))
202090075Sobrien			       (match_dup 4)))]
202190075Sobrien  "
202290075Sobrien  {
202390075Sobrien    operands[3] = gen_highpart (SImode, operands[0]);
202490075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
202590075Sobrien    operands[4] = gen_highpart (SImode, operands[1]);
202690075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
202790075Sobrien  }"
202890075Sobrien  [(set_attr "length" "8")
202990075Sobrien   (set_attr "predicable" "yes")]
203090075Sobrien)
203190075Sobrien  
203290075Sobrien(define_insn "andsi_notsi_si"
203390075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
203490075Sobrien	(and:SI (not:SI (match_operand:SI 2 "s_register_operand" "r"))
203590075Sobrien		(match_operand:SI 1 "s_register_operand" "r")))]
203690075Sobrien  "TARGET_ARM"
203790075Sobrien  "bic%?\\t%0, %1, %2"
203890075Sobrien  [(set_attr "predicable" "yes")]
203990075Sobrien)
204090075Sobrien
204190075Sobrien(define_insn "bicsi3"
204290075Sobrien  [(set (match_operand:SI                 0 "register_operand" "=l")
204390075Sobrien	(and:SI (not:SI (match_operand:SI 1 "register_operand" "l"))
204490075Sobrien		(match_operand:SI         2 "register_operand" "0")))]
204590075Sobrien  "TARGET_THUMB"
204690075Sobrien  "bic\\t%0, %0, %1"
204790075Sobrien  [(set_attr "length" "2")]
204890075Sobrien)
204990075Sobrien
205090075Sobrien(define_insn "andsi_not_shiftsi_si"
205190075Sobrien  [(set (match_operand:SI                   0 "s_register_operand" "=r")
205290075Sobrien	(and:SI (not:SI (match_operator:SI  4 "shift_operator"
205390075Sobrien			 [(match_operand:SI 2 "s_register_operand"  "r")
205490075Sobrien			  (match_operand:SI 3 "arm_rhs_operand"     "rM")]))
205590075Sobrien		(match_operand:SI           1 "s_register_operand"  "r")))]
205690075Sobrien  "TARGET_ARM"
205790075Sobrien  "bic%?\\t%0, %1, %2%S4"
205890075Sobrien  [(set_attr "predicable" "yes")
205990075Sobrien   (set_attr "shift" "2")
206090075Sobrien   ]
206190075Sobrien)
206290075Sobrien
206390075Sobrien(define_insn "*andsi_notsi_si_compare0"
206490075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
206590075Sobrien	(compare:CC_NOOV
206690075Sobrien	 (and:SI (not:SI (match_operand:SI 2 "s_register_operand" "r"))
206790075Sobrien		 (match_operand:SI 1 "s_register_operand" "r"))
206890075Sobrien	 (const_int 0)))
206990075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
207090075Sobrien	(and:SI (not:SI (match_dup 2)) (match_dup 1)))]
207190075Sobrien  "TARGET_ARM"
207290075Sobrien  "bic%?s\\t%0, %1, %2"
207390075Sobrien  [(set_attr "conds" "set")]
207490075Sobrien)
207590075Sobrien
207690075Sobrien(define_insn "*andsi_notsi_si_compare0_scratch"
207790075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
207890075Sobrien	(compare:CC_NOOV
207990075Sobrien	 (and:SI (not:SI (match_operand:SI 2 "s_register_operand" "r"))
208090075Sobrien		 (match_operand:SI 1 "s_register_operand" "r"))
208190075Sobrien	 (const_int 0)))
208290075Sobrien   (clobber (match_scratch:SI 0 "=r"))]
208390075Sobrien  "TARGET_ARM"
208490075Sobrien  "bic%?s\\t%0, %1, %2"
208590075Sobrien  [(set_attr "conds" "set")]
208690075Sobrien)
208790075Sobrien
208890075Sobrien(define_insn "iordi3"
208990075Sobrien  [(set (match_operand:DI         0 "s_register_operand" "=&r,&r")
209090075Sobrien	(ior:DI (match_operand:DI 1 "s_register_operand"  "%0,r")
209190075Sobrien		(match_operand:DI 2 "s_register_operand"   "r,r")))]
2092132718Skan  "TARGET_ARM && ! TARGET_IWMMXT"
209390075Sobrien  "#"
209490075Sobrien  [(set_attr "length" "8")
209590075Sobrien   (set_attr "predicable" "yes")]
209690075Sobrien)
209790075Sobrien
209890075Sobrien(define_insn "*iordi_zesidi_di"
209990075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
210090075Sobrien	(ior:DI (zero_extend:DI
210190075Sobrien		 (match_operand:SI 2 "s_register_operand" "r,r"))
210290075Sobrien		(match_operand:DI 1 "s_register_operand" "0,?r")))]
210390075Sobrien  "TARGET_ARM"
210490075Sobrien  "@
210590075Sobrien   orr%?\\t%Q0, %Q1, %2
210690075Sobrien   #"
210790075Sobrien  [(set_attr "length" "4,8")
210890075Sobrien   (set_attr "predicable" "yes")]
210990075Sobrien)
211090075Sobrien
211190075Sobrien(define_insn "*iordi_sesidi_di"
211290075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
211390075Sobrien	(ior:DI (sign_extend:DI
211490075Sobrien		 (match_operand:SI 2 "s_register_operand" "r,r"))
211590075Sobrien		(match_operand:DI 1 "s_register_operand" "?r,0")))]
211690075Sobrien  "TARGET_ARM"
211790075Sobrien  "#"
211890075Sobrien  [(set_attr "length" "8")
211990075Sobrien   (set_attr "predicable" "yes")]
212090075Sobrien)
212190075Sobrien
212290075Sobrien(define_expand "iorsi3"
212390075Sobrien  [(set (match_operand:SI         0 "s_register_operand" "")
212490075Sobrien	(ior:SI (match_operand:SI 1 "s_register_operand" "")
212590075Sobrien		(match_operand:SI 2 "reg_or_int_operand" "")))]
212690075Sobrien  "TARGET_EITHER"
212790075Sobrien  "
212890075Sobrien  if (GET_CODE (operands[2]) == CONST_INT)
212990075Sobrien    {
213090075Sobrien      if (TARGET_ARM)
213190075Sobrien        {
213290075Sobrien          arm_split_constant (IOR, SImode, INTVAL (operands[2]), operands[0],
213390075Sobrien		 	      operands[1],
213490075Sobrien			      (no_new_pseudos
213590075Sobrien			      ? 0 : preserve_subexpressions_p ()));
213690075Sobrien          DONE;
213790075Sobrien	}
213890075Sobrien      else /* TARGET_THUMB */
213990075Sobrien	operands [2] = force_reg (SImode, operands [2]);
214090075Sobrien    }
214190075Sobrien  "
214290075Sobrien)
214390075Sobrien
214490075Sobrien(define_insn_and_split "*arm_iorsi3"
214590075Sobrien  [(set (match_operand:SI         0 "s_register_operand" "=r,r")
214690075Sobrien	(ior:SI (match_operand:SI 1 "s_register_operand" "r,r")
214790075Sobrien		(match_operand:SI 2 "reg_or_int_operand" "rI,?n")))]
214890075Sobrien  "TARGET_ARM"
214990075Sobrien  "@
215090075Sobrien   orr%?\\t%0, %1, %2
215190075Sobrien   #"
215290075Sobrien  "TARGET_ARM
215390075Sobrien   && GET_CODE (operands[2]) == CONST_INT
215490075Sobrien   && !const_ok_for_arm (INTVAL (operands[2]))"
215590075Sobrien  [(clobber (const_int 0))]
215690075Sobrien  "
215790075Sobrien  arm_split_constant (IOR, SImode, INTVAL (operands[2]), operands[0],
215890075Sobrien		      operands[1], 0);
215990075Sobrien  DONE;
216090075Sobrien  "
216190075Sobrien  [(set_attr "length" "4,16")
216290075Sobrien   (set_attr "predicable" "yes")]
216390075Sobrien)
216490075Sobrien
216590075Sobrien(define_insn "*thumb_iorsi3"
216690075Sobrien  [(set (match_operand:SI         0 "register_operand" "=l")
216790075Sobrien	(ior:SI (match_operand:SI 1 "register_operand" "%0")
216890075Sobrien		(match_operand:SI 2 "register_operand" "l")))]
216990075Sobrien  "TARGET_THUMB"
217090075Sobrien  "orr\\t%0, %0, %2"
217190075Sobrien  [(set_attr "length" "2")]
217290075Sobrien)
217390075Sobrien
217490075Sobrien(define_peephole2
217590075Sobrien  [(match_scratch:SI 3 "r")
217690075Sobrien   (set (match_operand:SI         0 "s_register_operand" "")
217790075Sobrien	(ior:SI (match_operand:SI 1 "s_register_operand" "")
217890075Sobrien		(match_operand:SI 2 "const_int_operand" "")))]
217990075Sobrien  "TARGET_ARM
218090075Sobrien   && !const_ok_for_arm (INTVAL (operands[2]))
218190075Sobrien   && const_ok_for_arm (~INTVAL (operands[2]))"
218290075Sobrien  [(set (match_dup 3) (match_dup 2))
218390075Sobrien   (set (match_dup 0) (ior:SI (match_dup 1) (match_dup 3)))]
218490075Sobrien  ""
218590075Sobrien)
218690075Sobrien
218790075Sobrien(define_insn "*iorsi3_compare0"
218890075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
218990075Sobrien	(compare:CC_NOOV (ior:SI (match_operand:SI 1 "s_register_operand" "%r")
219090075Sobrien				 (match_operand:SI 2 "arm_rhs_operand" "rI"))
219190075Sobrien			 (const_int 0)))
219290075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
219390075Sobrien	(ior:SI (match_dup 1) (match_dup 2)))]
219490075Sobrien  "TARGET_ARM"
219590075Sobrien  "orr%?s\\t%0, %1, %2"
219690075Sobrien  [(set_attr "conds" "set")]
219790075Sobrien)
219890075Sobrien
219990075Sobrien(define_insn "*iorsi3_compare0_scratch"
220090075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
220190075Sobrien	(compare:CC_NOOV (ior:SI (match_operand:SI 1 "s_register_operand" "%r")
220290075Sobrien				 (match_operand:SI 2 "arm_rhs_operand" "rI"))
220390075Sobrien			 (const_int 0)))
220490075Sobrien   (clobber (match_scratch:SI 0 "=r"))]
220590075Sobrien  "TARGET_ARM"
220690075Sobrien  "orr%?s\\t%0, %1, %2"
220790075Sobrien  [(set_attr "conds" "set")]
220890075Sobrien)
220990075Sobrien
221090075Sobrien(define_insn "xordi3"
221190075Sobrien  [(set (match_operand:DI         0 "s_register_operand" "=&r,&r")
221290075Sobrien	(xor:DI (match_operand:DI 1 "s_register_operand"  "%0,r")
221390075Sobrien		(match_operand:DI 2 "s_register_operand"   "r,r")))]
2214132718Skan  "TARGET_ARM && !TARGET_IWMMXT"
221590075Sobrien  "#"
221690075Sobrien  [(set_attr "length" "8")
221790075Sobrien   (set_attr "predicable" "yes")]
221890075Sobrien)
221990075Sobrien
222090075Sobrien(define_insn "*xordi_zesidi_di"
222190075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
222290075Sobrien	(xor:DI (zero_extend:DI
222390075Sobrien		 (match_operand:SI 2 "s_register_operand" "r,r"))
222490075Sobrien		(match_operand:DI 1 "s_register_operand" "0,?r")))]
222590075Sobrien  "TARGET_ARM"
222690075Sobrien  "@
222790075Sobrien   eor%?\\t%Q0, %Q1, %2
222890075Sobrien   #"
222990075Sobrien  [(set_attr "length" "4,8")
223090075Sobrien   (set_attr "predicable" "yes")]
223190075Sobrien)
223290075Sobrien
223390075Sobrien(define_insn "*xordi_sesidi_di"
223490075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
223590075Sobrien	(xor:DI (sign_extend:DI
223690075Sobrien		 (match_operand:SI 2 "s_register_operand" "r,r"))
223790075Sobrien		(match_operand:DI 1 "s_register_operand" "?r,0")))]
223890075Sobrien  "TARGET_ARM"
223990075Sobrien  "#"
224090075Sobrien  [(set_attr "length" "8")
224190075Sobrien   (set_attr "predicable" "yes")]
224290075Sobrien)
224390075Sobrien
224490075Sobrien(define_expand "xorsi3"
224590075Sobrien  [(set (match_operand:SI         0 "s_register_operand" "")
224690075Sobrien	(xor:SI (match_operand:SI 1 "s_register_operand" "")
224790075Sobrien		(match_operand:SI 2 "arm_rhs_operand"  "")))]
224890075Sobrien  "TARGET_EITHER"
224990075Sobrien  "if (TARGET_THUMB)
225090075Sobrien     if (GET_CODE (operands[2]) == CONST_INT)
225190075Sobrien       operands[2] = force_reg (SImode, operands[2]);
225290075Sobrien  "
225390075Sobrien)
225490075Sobrien
225590075Sobrien(define_insn "*arm_xorsi3"
225690075Sobrien  [(set (match_operand:SI         0 "s_register_operand" "=r")
225790075Sobrien	(xor:SI (match_operand:SI 1 "s_register_operand" "r")
225890075Sobrien		(match_operand:SI 2 "arm_rhs_operand" "rI")))]
225990075Sobrien  "TARGET_ARM"
226090075Sobrien  "eor%?\\t%0, %1, %2"
226190075Sobrien  [(set_attr "predicable" "yes")]
226290075Sobrien)
226390075Sobrien
226490075Sobrien(define_insn "*thumb_xorsi3"
226590075Sobrien  [(set (match_operand:SI         0 "register_operand" "=l")
226690075Sobrien	(xor:SI (match_operand:SI 1 "register_operand" "%0")
226790075Sobrien		(match_operand:SI 2 "register_operand" "l")))]
226890075Sobrien  "TARGET_THUMB"
226990075Sobrien  "eor\\t%0, %0, %2"
227090075Sobrien  [(set_attr "length" "2")]
227190075Sobrien)
227290075Sobrien
227390075Sobrien(define_insn "*xorsi3_compare0"
227490075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
227590075Sobrien	(compare:CC_NOOV (xor:SI (match_operand:SI 1 "s_register_operand" "r")
227690075Sobrien				 (match_operand:SI 2 "arm_rhs_operand" "rI"))
227790075Sobrien			 (const_int 0)))
227890075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
227990075Sobrien	(xor:SI (match_dup 1) (match_dup 2)))]
228090075Sobrien  "TARGET_ARM"
228190075Sobrien  "eor%?s\\t%0, %1, %2"
228290075Sobrien  [(set_attr "conds" "set")]
228390075Sobrien)
228490075Sobrien
228590075Sobrien(define_insn "*xorsi3_compare0_scratch"
228690075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
228790075Sobrien	(compare:CC_NOOV (xor:SI (match_operand:SI 0 "s_register_operand" "r")
228890075Sobrien				 (match_operand:SI 1 "arm_rhs_operand" "rI"))
228990075Sobrien			 (const_int 0)))]
229090075Sobrien  "TARGET_ARM"
229190075Sobrien  "teq%?\\t%0, %1"
229290075Sobrien  [(set_attr "conds" "set")]
229390075Sobrien)
229490075Sobrien
229590075Sobrien; By splitting (IOR (AND (NOT A) (NOT B)) C) as D = AND (IOR A B) (NOT C), 
229690075Sobrien; (NOT D) we can sometimes merge the final NOT into one of the following
229790075Sobrien; insns.
229890075Sobrien
229990075Sobrien(define_split
2300117395Skan  [(set (match_operand:SI 0 "s_register_operand" "")
2301117395Skan	(ior:SI (and:SI (not:SI (match_operand:SI 1 "s_register_operand" ""))
2302117395Skan			(not:SI (match_operand:SI 2 "arm_rhs_operand" "")))
2303117395Skan		(match_operand:SI 3 "arm_rhs_operand" "")))
2304117395Skan   (clobber (match_operand:SI 4 "s_register_operand" ""))]
230590075Sobrien  "TARGET_ARM"
230690075Sobrien  [(set (match_dup 4) (and:SI (ior:SI (match_dup 1) (match_dup 2))
230790075Sobrien			      (not:SI (match_dup 3))))
230890075Sobrien   (set (match_dup 0) (not:SI (match_dup 4)))]
230990075Sobrien  ""
231090075Sobrien)
231190075Sobrien
231290075Sobrien(define_insn "*andsi_iorsi3_notsi"
231390075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r")
231490075Sobrien	(and:SI (ior:SI (match_operand:SI 1 "s_register_operand" "r,r,0")
231590075Sobrien			(match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))
231690075Sobrien		(not:SI (match_operand:SI 3 "arm_rhs_operand" "rI,rI,rI"))))]
231790075Sobrien  "TARGET_ARM"
231890075Sobrien  "orr%?\\t%0, %1, %2\;bic%?\\t%0, %0, %3"
231990075Sobrien  [(set_attr "length" "8")
232090075Sobrien   (set_attr "predicable" "yes")]
232190075Sobrien)
232290075Sobrien
2323132718Skan(define_split
2324132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
2325132718Skan	(match_operator:SI 1 "logical_binary_operator"
2326132718Skan	 [(zero_extract:SI (match_operand:SI 2 "s_register_operand" "")
2327132718Skan			   (match_operand:SI 3 "const_int_operand" "")
2328132718Skan			   (match_operand:SI 4 "const_int_operand" ""))
2329132718Skan	  (match_operator:SI 9 "logical_binary_operator"
2330132718Skan	   [(lshiftrt:SI (match_operand:SI 5 "s_register_operand" "")
2331132718Skan			 (match_operand:SI 6 "const_int_operand" ""))
2332132718Skan	    (match_operand:SI 7 "s_register_operand" "")])]))
2333132718Skan   (clobber (match_operand:SI 8 "s_register_operand" ""))]
2334132718Skan  "TARGET_ARM
2335132718Skan   && GET_CODE (operands[1]) == GET_CODE (operands[9])
2336132718Skan   && INTVAL (operands[3]) == 32 - INTVAL (operands[6])"
2337132718Skan  [(set (match_dup 8)
2338132718Skan	(match_op_dup 1
2339132718Skan	 [(ashift:SI (match_dup 2) (match_dup 4))
2340132718Skan	  (match_dup 5)]))
2341132718Skan   (set (match_dup 0)
2342132718Skan	(match_op_dup 1
2343132718Skan	 [(lshiftrt:SI (match_dup 8) (match_dup 6))
2344132718Skan	  (match_dup 7)]))]
2345132718Skan  "
2346132718Skan  operands[4] = GEN_INT (32 - (INTVAL (operands[3]) + INTVAL (operands[4])));
2347132718Skan")
2348132718Skan
2349132718Skan(define_split
2350132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
2351132718Skan	(match_operator:SI 1 "logical_binary_operator"
2352132718Skan	 [(match_operator:SI 9 "logical_binary_operator"
2353132718Skan	   [(lshiftrt:SI (match_operand:SI 5 "s_register_operand" "")
2354132718Skan			 (match_operand:SI 6 "const_int_operand" ""))
2355132718Skan	    (match_operand:SI 7 "s_register_operand" "")])
2356132718Skan	  (zero_extract:SI (match_operand:SI 2 "s_register_operand" "")
2357132718Skan			   (match_operand:SI 3 "const_int_operand" "")
2358132718Skan			   (match_operand:SI 4 "const_int_operand" ""))]))
2359132718Skan   (clobber (match_operand:SI 8 "s_register_operand" ""))]
2360132718Skan  "TARGET_ARM
2361132718Skan   && GET_CODE (operands[1]) == GET_CODE (operands[9])
2362132718Skan   && INTVAL (operands[3]) == 32 - INTVAL (operands[6])"
2363132718Skan  [(set (match_dup 8)
2364132718Skan	(match_op_dup 1
2365132718Skan	 [(ashift:SI (match_dup 2) (match_dup 4))
2366132718Skan	  (match_dup 5)]))
2367132718Skan   (set (match_dup 0)
2368132718Skan	(match_op_dup 1
2369132718Skan	 [(lshiftrt:SI (match_dup 8) (match_dup 6))
2370132718Skan	  (match_dup 7)]))]
2371132718Skan  "
2372132718Skan  operands[4] = GEN_INT (32 - (INTVAL (operands[3]) + INTVAL (operands[4])));
2373132718Skan")
2374132718Skan
2375132718Skan(define_split
2376132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
2377132718Skan	(match_operator:SI 1 "logical_binary_operator"
2378132718Skan	 [(sign_extract:SI (match_operand:SI 2 "s_register_operand" "")
2379132718Skan			   (match_operand:SI 3 "const_int_operand" "")
2380132718Skan			   (match_operand:SI 4 "const_int_operand" ""))
2381132718Skan	  (match_operator:SI 9 "logical_binary_operator"
2382132718Skan	   [(ashiftrt:SI (match_operand:SI 5 "s_register_operand" "")
2383132718Skan			 (match_operand:SI 6 "const_int_operand" ""))
2384132718Skan	    (match_operand:SI 7 "s_register_operand" "")])]))
2385132718Skan   (clobber (match_operand:SI 8 "s_register_operand" ""))]
2386132718Skan  "TARGET_ARM
2387132718Skan   && GET_CODE (operands[1]) == GET_CODE (operands[9])
2388132718Skan   && INTVAL (operands[3]) == 32 - INTVAL (operands[6])"
2389132718Skan  [(set (match_dup 8)
2390132718Skan	(match_op_dup 1
2391132718Skan	 [(ashift:SI (match_dup 2) (match_dup 4))
2392132718Skan	  (match_dup 5)]))
2393132718Skan   (set (match_dup 0)
2394132718Skan	(match_op_dup 1
2395132718Skan	 [(ashiftrt:SI (match_dup 8) (match_dup 6))
2396132718Skan	  (match_dup 7)]))]
2397132718Skan  "
2398132718Skan  operands[4] = GEN_INT (32 - (INTVAL (operands[3]) + INTVAL (operands[4])));
2399132718Skan")
2400132718Skan
2401132718Skan(define_split
2402132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
2403132718Skan	(match_operator:SI 1 "logical_binary_operator"
2404132718Skan	 [(match_operator:SI 9 "logical_binary_operator"
2405132718Skan	   [(ashiftrt:SI (match_operand:SI 5 "s_register_operand" "")
2406132718Skan			 (match_operand:SI 6 "const_int_operand" ""))
2407132718Skan	    (match_operand:SI 7 "s_register_operand" "")])
2408132718Skan	  (sign_extract:SI (match_operand:SI 2 "s_register_operand" "")
2409132718Skan			   (match_operand:SI 3 "const_int_operand" "")
2410132718Skan			   (match_operand:SI 4 "const_int_operand" ""))]))
2411132718Skan   (clobber (match_operand:SI 8 "s_register_operand" ""))]
2412132718Skan  "TARGET_ARM
2413132718Skan   && GET_CODE (operands[1]) == GET_CODE (operands[9])
2414132718Skan   && INTVAL (operands[3]) == 32 - INTVAL (operands[6])"
2415132718Skan  [(set (match_dup 8)
2416132718Skan	(match_op_dup 1
2417132718Skan	 [(ashift:SI (match_dup 2) (match_dup 4))
2418132718Skan	  (match_dup 5)]))
2419132718Skan   (set (match_dup 0)
2420132718Skan	(match_op_dup 1
2421132718Skan	 [(ashiftrt:SI (match_dup 8) (match_dup 6))
2422132718Skan	  (match_dup 7)]))]
2423132718Skan  "
2424132718Skan  operands[4] = GEN_INT (32 - (INTVAL (operands[3]) + INTVAL (operands[4])));
2425132718Skan")
242690075Sobrien
242790075Sobrien
242890075Sobrien;; Minimum and maximum insns
242990075Sobrien
243090075Sobrien(define_insn "smaxsi3"
243190075Sobrien  [(set (match_operand:SI          0 "s_register_operand" "=r,r,r")
243290075Sobrien	(smax:SI (match_operand:SI 1 "s_register_operand"  "0,r,?r")
243390075Sobrien		 (match_operand:SI 2 "arm_rhs_operand"    "rI,0,rI")))
243490075Sobrien   (clobber (reg:CC CC_REGNUM))]
243590075Sobrien  "TARGET_ARM"
243690075Sobrien  "@
243790075Sobrien   cmp\\t%1, %2\;movlt\\t%0, %2
243890075Sobrien   cmp\\t%1, %2\;movge\\t%0, %1
243990075Sobrien   cmp\\t%1, %2\;movge\\t%0, %1\;movlt\\t%0, %2"
244090075Sobrien  [(set_attr "conds" "clob")
244190075Sobrien   (set_attr "length" "8,8,12")]
244290075Sobrien)
244390075Sobrien
244490075Sobrien(define_insn "sminsi3"
244590075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
244690075Sobrien	(smin:SI (match_operand:SI 1 "s_register_operand" "0,r,?r")
244790075Sobrien		 (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")))
244890075Sobrien   (clobber (reg:CC CC_REGNUM))]
244990075Sobrien  "TARGET_ARM"
245090075Sobrien  "@
245190075Sobrien   cmp\\t%1, %2\;movge\\t%0, %2
245290075Sobrien   cmp\\t%1, %2\;movlt\\t%0, %1
245390075Sobrien   cmp\\t%1, %2\;movlt\\t%0, %1\;movge\\t%0, %2"
245490075Sobrien  [(set_attr "conds" "clob")
245590075Sobrien   (set_attr "length" "8,8,12")]
245690075Sobrien)
245790075Sobrien
245890075Sobrien(define_insn "umaxsi3"
245990075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
246090075Sobrien	(umax:SI (match_operand:SI 1 "s_register_operand" "0,r,?r")
246190075Sobrien		 (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")))
246290075Sobrien   (clobber (reg:CC CC_REGNUM))]
246390075Sobrien  "TARGET_ARM"
246490075Sobrien  "@
246590075Sobrien   cmp\\t%1, %2\;movcc\\t%0, %2
246690075Sobrien   cmp\\t%1, %2\;movcs\\t%0, %1
246790075Sobrien   cmp\\t%1, %2\;movcs\\t%0, %1\;movcc\\t%0, %2"
246890075Sobrien  [(set_attr "conds" "clob")
246990075Sobrien   (set_attr "length" "8,8,12")]
247090075Sobrien)
247190075Sobrien
247290075Sobrien(define_insn "uminsi3"
247390075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
247490075Sobrien	(umin:SI (match_operand:SI 1 "s_register_operand" "0,r,?r")
247590075Sobrien		 (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")))
247690075Sobrien   (clobber (reg:CC CC_REGNUM))]
247790075Sobrien  "TARGET_ARM"
247890075Sobrien  "@
247990075Sobrien   cmp\\t%1, %2\;movcs\\t%0, %2
248090075Sobrien   cmp\\t%1, %2\;movcc\\t%0, %1
248190075Sobrien   cmp\\t%1, %2\;movcc\\t%0, %1\;movcs\\t%0, %2"
248290075Sobrien  [(set_attr "conds" "clob")
248390075Sobrien   (set_attr "length" "8,8,12")]
248490075Sobrien)
248590075Sobrien
248690075Sobrien(define_insn "*store_minmaxsi"
248790075Sobrien  [(set (match_operand:SI 0 "memory_operand" "=m")
248890075Sobrien	(match_operator:SI 3 "minmax_operator"
248990075Sobrien	 [(match_operand:SI 1 "s_register_operand" "r")
249090075Sobrien	  (match_operand:SI 2 "s_register_operand" "r")]))
249190075Sobrien   (clobber (reg:CC CC_REGNUM))]
249290075Sobrien  "TARGET_ARM"
249390075Sobrien  "*
249490075Sobrien  operands[3] = gen_rtx (minmax_code (operands[3]), SImode, operands[1],
249590075Sobrien			 operands[2]);
249690075Sobrien  output_asm_insn (\"cmp\\t%1, %2\", operands);
249790075Sobrien  output_asm_insn (\"str%d3\\t%1, %0\", operands);
249890075Sobrien  output_asm_insn (\"str%D3\\t%2, %0\", operands);
249990075Sobrien  return \"\";
250090075Sobrien  "
250190075Sobrien  [(set_attr "conds" "clob")
250290075Sobrien   (set_attr "length" "12")
250390075Sobrien   (set_attr "type" "store1")]
250490075Sobrien)
250590075Sobrien
250690075Sobrien; Reject the frame pointer in operand[1], since reloading this after
250790075Sobrien; it has been eliminated can cause carnage.
250890075Sobrien(define_insn "*minmax_arithsi"
250990075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
251090075Sobrien	(match_operator:SI 4 "shiftable_operator"
251190075Sobrien	 [(match_operator:SI 5 "minmax_operator"
251290075Sobrien	   [(match_operand:SI 2 "s_register_operand" "r,r")
251390075Sobrien	    (match_operand:SI 3 "arm_rhs_operand" "rI,rI")])
251490075Sobrien	  (match_operand:SI 1 "s_register_operand" "0,?r")]))
251590075Sobrien   (clobber (reg:CC CC_REGNUM))]
251690075Sobrien  "TARGET_ARM
251790075Sobrien   && (GET_CODE (operands[1]) != REG
251890075Sobrien       || (REGNO(operands[1]) != FRAME_POINTER_REGNUM
251990075Sobrien           && REGNO(operands[1]) != ARG_POINTER_REGNUM))"
252090075Sobrien  "*
252190075Sobrien  {
252290075Sobrien    enum rtx_code code = GET_CODE (operands[4]);
252390075Sobrien
252490075Sobrien    operands[5] = gen_rtx (minmax_code (operands[5]), SImode, operands[2],
252590075Sobrien			   operands[3]);
252690075Sobrien    output_asm_insn (\"cmp\\t%2, %3\", operands);
252790075Sobrien    output_asm_insn (\"%i4%d5\\t%0, %1, %2\", operands);
252890075Sobrien    if (which_alternative != 0 || operands[3] != const0_rtx
252990075Sobrien        || (code != PLUS && code != MINUS && code != IOR && code != XOR))
253090075Sobrien      output_asm_insn (\"%i4%D5\\t%0, %1, %3\", operands);
253190075Sobrien    return \"\";
253290075Sobrien  }"
253390075Sobrien  [(set_attr "conds" "clob")
253490075Sobrien   (set_attr "length" "12")]
253590075Sobrien)
253690075Sobrien
253790075Sobrien
253890075Sobrien;; Shift and rotation insns
253990075Sobrien
254090075Sobrien(define_expand "ashlsi3"
254190075Sobrien  [(set (match_operand:SI            0 "s_register_operand" "")
254290075Sobrien	(ashift:SI (match_operand:SI 1 "s_register_operand" "")
254390075Sobrien		   (match_operand:SI 2 "arm_rhs_operand" "")))]
254490075Sobrien  "TARGET_EITHER"
254590075Sobrien  "
254690075Sobrien  if (GET_CODE (operands[2]) == CONST_INT
254790075Sobrien      && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31)
254890075Sobrien    {
254990075Sobrien      emit_insn (gen_movsi (operands[0], const0_rtx));
255090075Sobrien      DONE;
255190075Sobrien    }
255290075Sobrien  "
255390075Sobrien)
255490075Sobrien
255590075Sobrien(define_insn "*thumb_ashlsi3"
255690075Sobrien  [(set (match_operand:SI            0 "register_operand" "=l,l")
255790075Sobrien	(ashift:SI (match_operand:SI 1 "register_operand" "l,0")
255890075Sobrien		   (match_operand:SI 2 "nonmemory_operand" "N,l")))]
255990075Sobrien  "TARGET_THUMB"
256090075Sobrien  "lsl\\t%0, %1, %2"
256190075Sobrien  [(set_attr "length" "2")]
256290075Sobrien)
256390075Sobrien
256490075Sobrien(define_expand "ashrsi3"
256590075Sobrien  [(set (match_operand:SI              0 "s_register_operand" "")
256690075Sobrien	(ashiftrt:SI (match_operand:SI 1 "s_register_operand" "")
256790075Sobrien		     (match_operand:SI 2 "arm_rhs_operand" "")))]
256890075Sobrien  "TARGET_EITHER"
256990075Sobrien  "
257090075Sobrien  if (GET_CODE (operands[2]) == CONST_INT
257190075Sobrien      && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31)
257290075Sobrien    operands[2] = GEN_INT (31);
257390075Sobrien  "
257490075Sobrien)
257590075Sobrien
257690075Sobrien(define_insn "*thumb_ashrsi3"
257790075Sobrien  [(set (match_operand:SI              0 "register_operand" "=l,l")
257890075Sobrien	(ashiftrt:SI (match_operand:SI 1 "register_operand" "l,0")
257990075Sobrien		     (match_operand:SI 2 "nonmemory_operand" "N,l")))]
258090075Sobrien  "TARGET_THUMB"
258190075Sobrien  "asr\\t%0, %1, %2"
258290075Sobrien  [(set_attr "length" "2")]
258390075Sobrien)
258490075Sobrien
258590075Sobrien(define_expand "lshrsi3"
258690075Sobrien  [(set (match_operand:SI              0 "s_register_operand" "")
258790075Sobrien	(lshiftrt:SI (match_operand:SI 1 "s_register_operand" "")
258890075Sobrien		     (match_operand:SI 2 "arm_rhs_operand" "")))]
258990075Sobrien  "TARGET_EITHER"
259090075Sobrien  "
259190075Sobrien  if (GET_CODE (operands[2]) == CONST_INT
259290075Sobrien      && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31)
259390075Sobrien    {
259490075Sobrien      emit_insn (gen_movsi (operands[0], const0_rtx));
259590075Sobrien      DONE;
259690075Sobrien    }
259790075Sobrien  "
259890075Sobrien)
259990075Sobrien
260090075Sobrien(define_insn "*thumb_lshrsi3"
260190075Sobrien  [(set (match_operand:SI              0 "register_operand" "=l,l")
260290075Sobrien	(lshiftrt:SI (match_operand:SI 1 "register_operand" "l,0")
260390075Sobrien		     (match_operand:SI 2 "nonmemory_operand" "N,l")))]
260490075Sobrien  "TARGET_THUMB"
260590075Sobrien  "lsr\\t%0, %1, %2"
260690075Sobrien  [(set_attr "length" "2")]
260790075Sobrien)
260890075Sobrien
260990075Sobrien(define_expand "rotlsi3"
261090075Sobrien  [(set (match_operand:SI              0 "s_register_operand" "")
261190075Sobrien	(rotatert:SI (match_operand:SI 1 "s_register_operand" "")
261290075Sobrien		     (match_operand:SI 2 "reg_or_int_operand" "")))]
261390075Sobrien  "TARGET_ARM"
261490075Sobrien  "
261590075Sobrien  if (GET_CODE (operands[2]) == CONST_INT)
261690075Sobrien    operands[2] = GEN_INT ((32 - INTVAL (operands[2])) % 32);
261790075Sobrien  else
261890075Sobrien    {
261990075Sobrien      rtx reg = gen_reg_rtx (SImode);
262090075Sobrien      emit_insn (gen_subsi3 (reg, GEN_INT (32), operands[2]));
262190075Sobrien      operands[2] = reg;
262290075Sobrien    }
262390075Sobrien  "
262490075Sobrien)
262590075Sobrien
262690075Sobrien(define_expand "rotrsi3"
262790075Sobrien  [(set (match_operand:SI              0 "s_register_operand" "")
262890075Sobrien	(rotatert:SI (match_operand:SI 1 "s_register_operand" "")
262990075Sobrien		     (match_operand:SI 2 "arm_rhs_operand" "")))]
263090075Sobrien  "TARGET_EITHER"
263190075Sobrien  "
263290075Sobrien  if (TARGET_ARM)
263390075Sobrien    {
263490075Sobrien      if (GET_CODE (operands[2]) == CONST_INT
263590075Sobrien          && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31)
263690075Sobrien        operands[2] = GEN_INT (INTVAL (operands[2]) % 32);
263790075Sobrien    }
263890075Sobrien  else /* TARGET_THUMB */
263990075Sobrien    {
264090075Sobrien      if (GET_CODE (operands [2]) == CONST_INT)
264190075Sobrien        operands [2] = force_reg (SImode, operands[2]);
264290075Sobrien    }
264390075Sobrien  "
264490075Sobrien)
264590075Sobrien
264690075Sobrien(define_insn "*thumb_rotrsi3"
264790075Sobrien  [(set (match_operand:SI              0 "register_operand" "=l")
264890075Sobrien	(rotatert:SI (match_operand:SI 1 "register_operand" "0")
264990075Sobrien		     (match_operand:SI 2 "register_operand" "l")))]
265090075Sobrien  "TARGET_THUMB"
265190075Sobrien  "ror\\t%0, %0, %2"
265290075Sobrien  [(set_attr "length" "2")]
265390075Sobrien)
265490075Sobrien
2655132718Skan(define_expand "ashldi3"
2656132718Skan  [(set (match_operand:DI            0 "s_register_operand" "")
2657132718Skan	(ashift:DI (match_operand:DI 1 "general_operand"    "")
2658132718Skan		   (match_operand:SI 2 "general_operand"    "")))]
2659132718Skan  "TARGET_ARM && (TARGET_IWMMXT || TARGET_CIRRUS)"
2660132718Skan  "
2661132718Skan  if (! s_register_operand (operands[1], DImode))
2662132718Skan    operands[1] = copy_to_mode_reg (DImode, operands[1]);
2663132718Skan  if (! s_register_operand (operands[2], SImode))
2664132718Skan    operands[2] = copy_to_mode_reg (SImode, operands[2]);
2665132718Skan  "
2666132718Skan)
2667132718Skan
266890075Sobrien(define_insn "*arm_shiftsi3"
266990075Sobrien  [(set (match_operand:SI   0 "s_register_operand" "=r")
267090075Sobrien	(match_operator:SI  3 "shift_operator"
267190075Sobrien	 [(match_operand:SI 1 "s_register_operand"  "r")
267290075Sobrien	  (match_operand:SI 2 "reg_or_int_operand" "rM")]))]
267390075Sobrien  "TARGET_ARM"
267490075Sobrien  "mov%?\\t%0, %1%S3"
267590075Sobrien  [(set_attr "predicable" "yes")
267690075Sobrien   (set_attr "shift" "1")
267790075Sobrien   ]
267890075Sobrien)
267990075Sobrien
268090075Sobrien(define_insn "*shiftsi3_compare0"
268190075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
268290075Sobrien	(compare:CC_NOOV (match_operator:SI 3 "shift_operator"
268390075Sobrien			  [(match_operand:SI 1 "s_register_operand" "r")
268490075Sobrien			   (match_operand:SI 2 "arm_rhs_operand" "rM")])
268590075Sobrien			 (const_int 0)))
268690075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
268790075Sobrien	(match_op_dup 3 [(match_dup 1) (match_dup 2)]))]
268890075Sobrien  "TARGET_ARM"
268990075Sobrien  "mov%?s\\t%0, %1%S3"
269090075Sobrien  [(set_attr "conds" "set")
269190075Sobrien   (set_attr "shift" "1")
269290075Sobrien   ]
269390075Sobrien)
269490075Sobrien
269590075Sobrien(define_insn "*shiftsi3_compare0_scratch"
269690075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
269790075Sobrien	(compare:CC_NOOV (match_operator:SI 3 "shift_operator"
269890075Sobrien			  [(match_operand:SI 1 "s_register_operand" "r")
269990075Sobrien			   (match_operand:SI 2 "arm_rhs_operand" "rM")])
270090075Sobrien			 (const_int 0)))
270190075Sobrien   (clobber (match_scratch:SI 0 "=r"))]
270290075Sobrien  "TARGET_ARM"
270390075Sobrien  "mov%?s\\t%0, %1%S3"
270490075Sobrien  [(set_attr "conds" "set")
270590075Sobrien   (set_attr "shift" "1")
270690075Sobrien   ]
270790075Sobrien)
270890075Sobrien
270990075Sobrien(define_insn "*notsi_shiftsi"
271090075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
271190075Sobrien	(not:SI (match_operator:SI 3 "shift_operator"
271290075Sobrien		 [(match_operand:SI 1 "s_register_operand" "r")
271390075Sobrien		  (match_operand:SI 2 "arm_rhs_operand" "rM")])))]
271490075Sobrien  "TARGET_ARM"
271590075Sobrien  "mvn%?\\t%0, %1%S3"
271690075Sobrien  [(set_attr "predicable" "yes")
271790075Sobrien   (set_attr "shift" "1")
271890075Sobrien   ]
271990075Sobrien)
272090075Sobrien
272190075Sobrien(define_insn "*notsi_shiftsi_compare0"
272290075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
272390075Sobrien	(compare:CC_NOOV (not:SI (match_operator:SI 3 "shift_operator"
272490075Sobrien			  [(match_operand:SI 1 "s_register_operand" "r")
272590075Sobrien			   (match_operand:SI 2 "arm_rhs_operand" "rM")]))
272690075Sobrien			 (const_int 0)))
272790075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
272890075Sobrien	(not:SI (match_op_dup 3 [(match_dup 1) (match_dup 2)])))]
272990075Sobrien  "TARGET_ARM"
273090075Sobrien  "mvn%?s\\t%0, %1%S3"
273190075Sobrien  [(set_attr "conds" "set")
273290075Sobrien   (set_attr "shift" "1")
273390075Sobrien   ]
273490075Sobrien)
273590075Sobrien
273690075Sobrien(define_insn "*not_shiftsi_compare0_scratch"
273790075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
273890075Sobrien	(compare:CC_NOOV (not:SI (match_operator:SI 3 "shift_operator"
273990075Sobrien			  [(match_operand:SI 1 "s_register_operand" "r")
274090075Sobrien			   (match_operand:SI 2 "arm_rhs_operand" "rM")]))
274190075Sobrien			 (const_int 0)))
274290075Sobrien   (clobber (match_scratch:SI 0 "=r"))]
274390075Sobrien  "TARGET_ARM"
274490075Sobrien  "mvn%?s\\t%0, %1%S3"
274590075Sobrien  [(set_attr "conds" "set")
274690075Sobrien   (set_attr "shift" "1")
274790075Sobrien  ]
274890075Sobrien)
274990075Sobrien
275090075Sobrien;; We don't really have extzv, but defining this using shifts helps
275190075Sobrien;; to reduce register pressure later on.
275290075Sobrien
275390075Sobrien(define_expand "extzv"
275490075Sobrien  [(set (match_dup 4)
275590075Sobrien	(ashift:SI (match_operand:SI   1 "register_operand" "")
275690075Sobrien		   (match_operand:SI   2 "const_int_operand" "")))
275790075Sobrien   (set (match_operand:SI              0 "register_operand" "")
275890075Sobrien	(lshiftrt:SI (match_dup 4)
275990075Sobrien		     (match_operand:SI 3 "const_int_operand" "")))]
276090075Sobrien  "TARGET_THUMB"
276190075Sobrien  "
276290075Sobrien  {
276390075Sobrien    HOST_WIDE_INT lshift = 32 - INTVAL (operands[2]) - INTVAL (operands[3]);
276490075Sobrien    HOST_WIDE_INT rshift = 32 - INTVAL (operands[2]);
276590075Sobrien    
276690075Sobrien    operands[3] = GEN_INT (rshift);
276790075Sobrien    
276890075Sobrien    if (lshift == 0)
276990075Sobrien      {
277090075Sobrien        emit_insn (gen_lshrsi3 (operands[0], operands[1], operands[3]));
277190075Sobrien        DONE;
277290075Sobrien      }
277390075Sobrien      
277490075Sobrien    operands[2] = GEN_INT (lshift);
277590075Sobrien    operands[4] = gen_reg_rtx (SImode);
277690075Sobrien  }"
277790075Sobrien)
277890075Sobrien
277990075Sobrien
278090075Sobrien;; Unary arithmetic insns
278190075Sobrien
278290075Sobrien(define_expand "negdi2"
278390075Sobrien [(parallel
278490075Sobrien   [(set (match_operand:DI          0 "s_register_operand" "")
278590075Sobrien	  (neg:DI (match_operand:DI 1 "s_register_operand" "")))
278690075Sobrien    (clobber (reg:CC CC_REGNUM))])]
278790075Sobrien  "TARGET_EITHER"
278890075Sobrien  "
278990075Sobrien  if (TARGET_THUMB)
279090075Sobrien    {
279190075Sobrien      if (GET_CODE (operands[1]) != REG)
279290075Sobrien        operands[1] = force_reg (SImode, operands[1]);
279390075Sobrien     }
279490075Sobrien  "
279590075Sobrien)
279690075Sobrien
279790075Sobrien;; The constraints here are to prevent a *partial* overlap (where %Q0 == %R1).
279890075Sobrien;; The second alternative is to allow the common case of a *full* overlap.
279990075Sobrien(define_insn "*arm_negdi2"
280090075Sobrien  [(set (match_operand:DI         0 "s_register_operand" "=&r,r")
280190075Sobrien	(neg:DI (match_operand:DI 1 "s_register_operand"  "?r,0")))
280290075Sobrien   (clobber (reg:CC CC_REGNUM))]
280390075Sobrien  "TARGET_ARM"
280490075Sobrien  "rsbs\\t%Q0, %Q1, #0\;rsc\\t%R0, %R1, #0"
280590075Sobrien  [(set_attr "conds" "clob")
280690075Sobrien   (set_attr "length" "8")]
280790075Sobrien)
280890075Sobrien
280990075Sobrien(define_insn "*thumb_negdi2"
281090075Sobrien  [(set (match_operand:DI         0 "register_operand" "=&l")
281190075Sobrien	(neg:DI (match_operand:DI 1 "register_operand"   "l")))
281290075Sobrien   (clobber (reg:CC CC_REGNUM))]
281390075Sobrien  "TARGET_THUMB"
281490075Sobrien  "mov\\t%R0, #0\;neg\\t%Q0, %Q1\;sbc\\t%R0, %R1"
281590075Sobrien  [(set_attr "length" "6")]
281690075Sobrien)
281790075Sobrien
281890075Sobrien(define_expand "negsi2"
281990075Sobrien  [(set (match_operand:SI         0 "s_register_operand" "")
282090075Sobrien	(neg:SI (match_operand:SI 1 "s_register_operand" "")))]
282190075Sobrien  "TARGET_EITHER"
282290075Sobrien  ""
282390075Sobrien)
282490075Sobrien
282590075Sobrien(define_insn "*arm_negsi2"
282690075Sobrien  [(set (match_operand:SI         0 "s_register_operand" "=r")
282790075Sobrien	(neg:SI (match_operand:SI 1 "s_register_operand" "r")))]
282890075Sobrien  "TARGET_ARM"
282990075Sobrien  "rsb%?\\t%0, %1, #0"
283090075Sobrien  [(set_attr "predicable" "yes")]
283190075Sobrien)
283290075Sobrien
283390075Sobrien(define_insn "*thumb_negsi2"
283490075Sobrien  [(set (match_operand:SI         0 "register_operand" "=l")
283590075Sobrien	(neg:SI (match_operand:SI 1 "register_operand" "l")))]
283690075Sobrien  "TARGET_THUMB"
283790075Sobrien  "neg\\t%0, %1"
283890075Sobrien  [(set_attr "length" "2")]
283990075Sobrien)
284090075Sobrien
2841132718Skan(define_expand "negsf2"
2842132718Skan  [(set (match_operand:SF         0 "s_register_operand" "")
2843132718Skan	(neg:SF (match_operand:SF 1 "s_register_operand" "")))]
2844132718Skan  "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
2845132718Skan  ""
284690075Sobrien)
284790075Sobrien
2848132718Skan(define_expand "negdf2"
2849132718Skan  [(set (match_operand:DF         0 "s_register_operand" "")
2850132718Skan	(neg:DF (match_operand:DF 1 "s_register_operand" "")))]
2851132718Skan  "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
2852132718Skan  "")
285390075Sobrien
285490075Sobrien;; abssi2 doesn't really clobber the condition codes if a different register
285590075Sobrien;; is being set.  To keep things simple, assume during rtl manipulations that
285690075Sobrien;; it does, but tell the final scan operator the truth.  Similarly for
285790075Sobrien;; (neg (abs...))
285890075Sobrien
2859132718Skan(define_expand "abssi2"
2860132718Skan  [(parallel
2861132718Skan    [(set (match_operand:SI         0 "s_register_operand" "")
2862132718Skan	  (abs:SI (match_operand:SI 1 "s_register_operand" "")))
2863132718Skan     (clobber (reg:CC CC_REGNUM))])]
2864132718Skan  "TARGET_ARM"
2865132718Skan  "")
2866132718Skan
2867132718Skan(define_insn "*arm_abssi2"
286890075Sobrien  [(set (match_operand:SI         0 "s_register_operand" "=r,&r")
286990075Sobrien	(abs:SI (match_operand:SI 1 "s_register_operand" "0,r")))
287090075Sobrien   (clobber (reg:CC CC_REGNUM))]
287190075Sobrien  "TARGET_ARM"
287290075Sobrien  "@
287390075Sobrien   cmp\\t%0, #0\;rsblt\\t%0, %0, #0
287490075Sobrien   eor%?\\t%0, %1, %1, asr #31\;sub%?\\t%0, %0, %1, asr #31"
287590075Sobrien  [(set_attr "conds" "clob,*")
287690075Sobrien   (set_attr "shift" "1")
287790075Sobrien   ;; predicable can't be set based on the variant, so left as no
287890075Sobrien   (set_attr "length" "8")]
287990075Sobrien)
288090075Sobrien
288190075Sobrien(define_insn "*neg_abssi2"
288290075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,&r")
288390075Sobrien	(neg:SI (abs:SI (match_operand:SI 1 "s_register_operand" "0,r"))))
288490075Sobrien   (clobber (reg:CC CC_REGNUM))]
288590075Sobrien  "TARGET_ARM"
288690075Sobrien  "@
288790075Sobrien   cmp\\t%0, #0\;rsbgt\\t%0, %0, #0
288890075Sobrien   eor%?\\t%0, %1, %1, asr #31\;rsb%?\\t%0, %0, %1, asr #31"
288990075Sobrien  [(set_attr "conds" "clob,*")
289090075Sobrien   (set_attr "shift" "1")
289190075Sobrien   ;; predicable can't be set based on the variant, so left as no
289290075Sobrien   (set_attr "length" "8")]
289390075Sobrien)
289490075Sobrien
2895132718Skan(define_expand "abssf2"
2896132718Skan  [(set (match_operand:SF         0 "s_register_operand" "")
2897132718Skan	(abs:SF (match_operand:SF 1 "s_register_operand" "")))]
2898132718Skan  "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
2899132718Skan  "")
290090075Sobrien
2901132718Skan(define_expand "absdf2"
2902132718Skan  [(set (match_operand:DF         0 "s_register_operand" "")
2903132718Skan	(abs:DF (match_operand:DF 1 "s_register_operand" "")))]
2904132718Skan  "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
2905132718Skan  "")
290690075Sobrien
2907132718Skan(define_expand "sqrtsf2"
2908132718Skan  [(set (match_operand:SF 0 "s_register_operand" "")
2909132718Skan	(sqrt:SF (match_operand:SF 1 "s_register_operand" "")))]
291090075Sobrien  "TARGET_ARM && TARGET_HARD_FLOAT"
2911132718Skan  "")
291290075Sobrien
2913132718Skan(define_expand "sqrtdf2"
2914132718Skan  [(set (match_operand:DF 0 "s_register_operand" "")
2915132718Skan	(sqrt:DF (match_operand:DF 1 "s_register_operand" "")))]
291690075Sobrien  "TARGET_ARM && TARGET_HARD_FLOAT"
2917132718Skan  "")
291890075Sobrien
291990075Sobrien(define_insn_and_split "one_cmpldi2"
292090075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
292190075Sobrien	(not:DI (match_operand:DI 1 "s_register_operand" "?r,0")))]
292290075Sobrien  "TARGET_ARM"
292390075Sobrien  "#"
292490075Sobrien  "TARGET_ARM && reload_completed"
292590075Sobrien  [(set (match_dup 0) (not:SI (match_dup 1)))
292690075Sobrien   (set (match_dup 2) (not:SI (match_dup 3)))]
292790075Sobrien  "
292890075Sobrien  {
292990075Sobrien    operands[2] = gen_highpart (SImode, operands[0]);
293090075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
293190075Sobrien    operands[3] = gen_highpart (SImode, operands[1]);
293290075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
293390075Sobrien  }"
293490075Sobrien  [(set_attr "length" "8")
293590075Sobrien   (set_attr "predicable" "yes")]
293690075Sobrien)
293790075Sobrien
293890075Sobrien(define_expand "one_cmplsi2"
293990075Sobrien  [(set (match_operand:SI         0 "s_register_operand" "")
294090075Sobrien	(not:SI (match_operand:SI 1 "s_register_operand" "")))]
294190075Sobrien  "TARGET_EITHER"
294290075Sobrien  ""
294390075Sobrien)
294490075Sobrien
294590075Sobrien(define_insn "*arm_one_cmplsi2"
294690075Sobrien  [(set (match_operand:SI         0 "s_register_operand" "=r")
294790075Sobrien	(not:SI (match_operand:SI 1 "s_register_operand"  "r")))]
294890075Sobrien  "TARGET_ARM"
294990075Sobrien  "mvn%?\\t%0, %1"
295090075Sobrien  [(set_attr "predicable" "yes")]
295190075Sobrien)
295290075Sobrien
295390075Sobrien(define_insn "*thumb_one_cmplsi2"
295490075Sobrien  [(set (match_operand:SI         0 "register_operand" "=l")
295590075Sobrien	(not:SI (match_operand:SI 1 "register_operand"  "l")))]
295690075Sobrien  "TARGET_THUMB"
295790075Sobrien  "mvn\\t%0, %1"
295890075Sobrien  [(set_attr "length" "2")]
295990075Sobrien)
296090075Sobrien
296190075Sobrien(define_insn "*notsi_compare0"
296290075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
296390075Sobrien	(compare:CC_NOOV (not:SI (match_operand:SI 1 "s_register_operand" "r"))
296490075Sobrien			 (const_int 0)))
296590075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
296690075Sobrien	(not:SI (match_dup 1)))]
296790075Sobrien  "TARGET_ARM"
296890075Sobrien  "mvn%?s\\t%0, %1"
296990075Sobrien  [(set_attr "conds" "set")]
297090075Sobrien)
297190075Sobrien
297290075Sobrien(define_insn "*notsi_compare0_scratch"
297390075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
297490075Sobrien	(compare:CC_NOOV (not:SI (match_operand:SI 1 "s_register_operand" "r"))
297590075Sobrien			 (const_int 0)))
297690075Sobrien   (clobber (match_scratch:SI 0 "=r"))]
297790075Sobrien  "TARGET_ARM"
297890075Sobrien  "mvn%?s\\t%0, %1"
297990075Sobrien  [(set_attr "conds" "set")]
298090075Sobrien)
298190075Sobrien
298290075Sobrien;; Fixed <--> Floating conversion insns
298390075Sobrien
2984132718Skan(define_expand "floatsisf2"
2985132718Skan  [(set (match_operand:SF           0 "s_register_operand" "")
2986132718Skan	(float:SF (match_operand:SI 1 "s_register_operand" "")))]
2987132718Skan  "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
2988132718Skan  "
2989132718Skan  if (TARGET_CIRRUS)
2990132718Skan    {
2991132718Skan      emit_insn (gen_cirrus_floatsisf2 (operands[0], operands[1]));
2992132718Skan      DONE;
2993132718Skan    }
2994132718Skan")
299590075Sobrien
2996132718Skan(define_expand "floatsidf2"
2997132718Skan  [(set (match_operand:DF           0 "s_register_operand" "")
2998132718Skan	(float:DF (match_operand:SI 1 "s_register_operand" "")))]
2999132718Skan  "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
3000132718Skan  "
3001132718Skan  if (TARGET_CIRRUS)
3002132718Skan    {
3003132718Skan      emit_insn (gen_cirrus_floatsidf2 (operands[0], operands[1]));
3004132718Skan      DONE;
3005132718Skan    }
3006132718Skan")
300790075Sobrien
3008132718Skan(define_expand "fix_truncsfsi2"
3009132718Skan  [(set (match_operand:SI         0 "s_register_operand" "")
3010132718Skan	(fix:SI (fix:SF (match_operand:SF 1 "s_register_operand"  ""))))]
3011132718Skan  "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
3012132718Skan  "
3013132718Skan  if (TARGET_CIRRUS)
3014132718Skan    {
3015132718Skan      if (!cirrus_fp_register (operands[0], SImode))
3016132718Skan        operands[0] = force_reg (SImode, operands[0]);
3017132718Skan      if (!cirrus_fp_register (operands[1], SFmode))
3018132718Skan        operands[1] = force_reg (SFmode, operands[0]);
3019132718Skan      emit_insn (gen_cirrus_truncsfsi2 (operands[0], operands[1]));
3020132718Skan      DONE;
3021132718Skan    }
3022132718Skan")
302390075Sobrien
3024132718Skan(define_expand "fix_truncdfsi2"
3025132718Skan  [(set (match_operand:SI         0 "s_register_operand" "")
3026132718Skan	(fix:SI (fix:DF (match_operand:DF 1 "s_register_operand"  ""))))]
3027132718Skan  "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
3028132718Skan  "
3029132718Skan  if (TARGET_CIRRUS)
3030132718Skan    {
3031132718Skan      if (!cirrus_fp_register (operands[1], DFmode))
3032132718Skan        operands[1] = force_reg (DFmode, operands[0]);
3033132718Skan      emit_insn (gen_cirrus_truncdfsi2 (operands[0], operands[1]));
3034132718Skan      DONE;
3035132718Skan    }
3036132718Skan")
303790075Sobrien
303890075Sobrien;; Truncation insns
303990075Sobrien
3040132718Skan(define_expand "truncdfsf2"
3041132718Skan  [(set (match_operand:SF  0 "s_register_operand" "")
304290075Sobrien	(float_truncate:SF
3043132718Skan 	 (match_operand:DF 1 "s_register_operand" "")))]
3044132718Skan  "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
3045132718Skan  ""
304690075Sobrien)
304790075Sobrien
304890075Sobrien;; Zero and sign extension instructions.
304990075Sobrien
305090075Sobrien(define_insn "zero_extendsidi2"
305190075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=r")
305290075Sobrien        (zero_extend:DI (match_operand:SI 1 "s_register_operand" "r")))]
305390075Sobrien  "TARGET_ARM"
305490075Sobrien  "*
305590075Sobrien    if (REGNO (operands[1])
305690075Sobrien        != REGNO (operands[0]) + (WORDS_BIG_ENDIAN ? 1 : 0))
305790075Sobrien      output_asm_insn (\"mov%?\\t%Q0, %1\", operands);
305890075Sobrien    return \"mov%?\\t%R0, #0\";
305990075Sobrien  "
306090075Sobrien  [(set_attr "length" "8")
306190075Sobrien   (set_attr "predicable" "yes")]
306290075Sobrien)
306390075Sobrien
306490075Sobrien(define_insn "zero_extendqidi2"
306590075Sobrien  [(set (match_operand:DI                 0 "s_register_operand"  "=r,r")
306690075Sobrien	(zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
306790075Sobrien  "TARGET_ARM"
306890075Sobrien  "@
306990075Sobrien   and%?\\t%Q0, %1, #255\;mov%?\\t%R0, #0
307090075Sobrien   ldr%?b\\t%Q0, %1\;mov%?\\t%R0, #0"
307190075Sobrien  [(set_attr "length" "8")
307290075Sobrien   (set_attr "predicable" "yes")
307390075Sobrien   (set_attr "type" "*,load")
307490075Sobrien   (set_attr "pool_range" "*,4092")
307590075Sobrien   (set_attr "neg_pool_range" "*,4084")]
307690075Sobrien)
307790075Sobrien
307890075Sobrien(define_insn "extendsidi2"
307990075Sobrien  [(set (match_operand:DI 0 "s_register_operand" "=r")
308090075Sobrien        (sign_extend:DI (match_operand:SI 1 "s_register_operand" "r")))]
308190075Sobrien  "TARGET_ARM"
308290075Sobrien  "*
308390075Sobrien    if (REGNO (operands[1])
308490075Sobrien        != REGNO (operands[0]) + (WORDS_BIG_ENDIAN ? 1 : 0))
308590075Sobrien      output_asm_insn (\"mov%?\\t%Q0, %1\", operands);
308690075Sobrien    return \"mov%?\\t%R0, %Q0, asr #31\";
308790075Sobrien  "
308890075Sobrien  [(set_attr "length" "8")
308990075Sobrien   (set_attr "shift" "1")
309090075Sobrien   (set_attr "predicable" "yes")]
309190075Sobrien)
309290075Sobrien
309390075Sobrien(define_expand "zero_extendhisi2"
309490075Sobrien  [(set (match_dup 2)
309590075Sobrien	(ashift:SI (match_operand:HI 1 "nonimmediate_operand" "")
309690075Sobrien		   (const_int 16)))
309790075Sobrien   (set (match_operand:SI 0 "s_register_operand" "")
309890075Sobrien	(lshiftrt:SI (match_dup 2) (const_int 16)))]
309990075Sobrien  "TARGET_EITHER"
310090075Sobrien  "
310190075Sobrien  {
310290075Sobrien    if (TARGET_ARM)
310390075Sobrien      {
310490075Sobrien        if (arm_arch4 && GET_CODE (operands[1]) == MEM)
310590075Sobrien          {
310690075Sobrien           /* Note: We do not have to worry about TARGET_MMU_TRAPS
310790075Sobrien	      here because the insn below will generate an LDRH instruction
310890075Sobrien	      rather than an LDR instruction, so we cannot get an unaligned
310990075Sobrien	      word access.  */
311090075Sobrien            emit_insn (gen_rtx_SET (VOIDmode, operands[0],
311190075Sobrien			            gen_rtx_ZERO_EXTEND (SImode,
311290075Sobrien							 operands[1])));
311390075Sobrien            DONE;
311490075Sobrien          }
311590075Sobrien        if (TARGET_MMU_TRAPS && GET_CODE (operands[1]) == MEM)
311690075Sobrien          {
311790075Sobrien            emit_insn (gen_movhi_bytes (operands[0], operands[1]));
311890075Sobrien            DONE;
311990075Sobrien          }
312090075Sobrien        if (!s_register_operand (operands[1], HImode))
312190075Sobrien          operands[1] = copy_to_mode_reg (HImode, operands[1]);
312290075Sobrien        operands[1] = gen_lowpart (SImode, operands[1]);
312390075Sobrien        operands[2] = gen_reg_rtx (SImode);
312490075Sobrien      }
312590075Sobrien    else /* TARGET_THUMB */
312690075Sobrien      {
312790075Sobrien        if (GET_CODE (operands[1]) == MEM)
312890075Sobrien	  {
312990075Sobrien	    rtx tmp;
313090075Sobrien
313190075Sobrien	    tmp = gen_rtx_ZERO_EXTEND (SImode, operands[1]);
313290075Sobrien	    tmp = gen_rtx_SET (VOIDmode, operands[0], tmp);
313390075Sobrien	    emit_insn (tmp);
313490075Sobrien	  }
313590075Sobrien	else
313690075Sobrien	  {
313790075Sobrien	    rtx ops[3];
313890075Sobrien	    
313990075Sobrien	    if (!s_register_operand (operands[1], HImode))
314090075Sobrien	      operands[1] = copy_to_mode_reg (HImode, operands[1]);
314190075Sobrien	    operands[1] = gen_lowpart (SImode, operands[1]);
314290075Sobrien	    operands[2] = gen_reg_rtx (SImode);
314390075Sobrien	    
314490075Sobrien	    ops[0] = operands[2];
314590075Sobrien	    ops[1] = operands[1];
314690075Sobrien	    ops[2] = GEN_INT (16);
314790075Sobrien	    
314890075Sobrien	    emit_insn (gen_rtx_SET (VOIDmode, ops[0],
314990075Sobrien				    gen_rtx_ASHIFT (SImode, ops[1], ops[2])));
315090075Sobrien
315190075Sobrien	    ops[0] = operands[0];
315290075Sobrien	    ops[1] = operands[2];
315390075Sobrien	    ops[2] = GEN_INT (16);
315490075Sobrien
315590075Sobrien	    emit_insn (gen_rtx_SET (VOIDmode, ops[0],
315690075Sobrien				    gen_rtx_LSHIFTRT (SImode, ops[1],
315790075Sobrien						      ops[2])));
315890075Sobrien	  }
315990075Sobrien	DONE; 
316090075Sobrien      }
316190075Sobrien  }"
316290075Sobrien)
316390075Sobrien
316490075Sobrien(define_insn "*thumb_zero_extendhisi2"
316590075Sobrien  [(set (match_operand:SI                 0 "register_operand" "=l")
316690075Sobrien	(zero_extend:SI (match_operand:HI 1 "memory_operand"    "m")))]
316790075Sobrien  "TARGET_THUMB"
316890075Sobrien  "*
316990075Sobrien  rtx mem = XEXP (operands[1], 0);
317090075Sobrien
317190075Sobrien  if (GET_CODE (mem) == CONST)
317290075Sobrien    mem = XEXP (mem, 0);
317390075Sobrien    
317490075Sobrien  if (GET_CODE (mem) == LABEL_REF)
317590075Sobrien    return \"ldr\\t%0, %1\";
317690075Sobrien    
317790075Sobrien  if (GET_CODE (mem) == PLUS)
317890075Sobrien    {
317990075Sobrien      rtx a = XEXP (mem, 0);
318090075Sobrien      rtx b = XEXP (mem, 1);
318190075Sobrien
318290075Sobrien      /* This can happen due to bugs in reload.  */
318390075Sobrien      if (GET_CODE (a) == REG && REGNO (a) == SP_REGNUM)
318490075Sobrien        {
318590075Sobrien          rtx ops[2];
318690075Sobrien          ops[0] = operands[0];
318790075Sobrien          ops[1] = a;
318890075Sobrien      
318990075Sobrien          output_asm_insn (\"mov	%0, %1\", ops);
319090075Sobrien
319190075Sobrien          XEXP (mem, 0) = operands[0];
319290075Sobrien       }
319390075Sobrien
319490075Sobrien      else if (   GET_CODE (a) == LABEL_REF
319590075Sobrien	       && GET_CODE (b) == CONST_INT)
319690075Sobrien        return \"ldr\\t%0, %1\";
319790075Sobrien    }
319890075Sobrien    
319990075Sobrien  return \"ldrh\\t%0, %1\";
320090075Sobrien  "
320190075Sobrien  [(set_attr "length" "4")
320290075Sobrien   (set_attr "type" "load")
320390075Sobrien   (set_attr "pool_range" "60")]
320490075Sobrien)
320590075Sobrien
320690075Sobrien(define_insn "*arm_zero_extendhisi2"
320790075Sobrien  [(set (match_operand:SI                 0 "s_register_operand" "=r")
320890075Sobrien	(zero_extend:SI (match_operand:HI 1 "memory_operand"      "m")))]
320990075Sobrien  "TARGET_ARM && arm_arch4"
321090075Sobrien  "ldr%?h\\t%0, %1"
321190075Sobrien  [(set_attr "type" "load")
321290075Sobrien   (set_attr "predicable" "yes")
321390075Sobrien   (set_attr "pool_range" "256")
321490075Sobrien   (set_attr "neg_pool_range" "244")]
321590075Sobrien)
321690075Sobrien
321790075Sobrien(define_split
321890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
321990075Sobrien	(zero_extend:SI (match_operand:HI 1 "alignable_memory_operand" "")))
322090075Sobrien   (clobber (match_operand:SI 2 "s_register_operand" ""))]
322190075Sobrien  "TARGET_ARM && (!arm_arch4)"
322290075Sobrien  [(set (match_dup 2) (match_dup 1))
322390075Sobrien   (set (match_dup 0) (lshiftrt:SI (match_dup 2) (const_int 16)))]
322490075Sobrien  "
322590075Sobrien  if ((operands[1] = arm_gen_rotated_half_load (operands[1])) == NULL)
322690075Sobrien    FAIL;
322790075Sobrien  "
322890075Sobrien)
322990075Sobrien
323090075Sobrien(define_split
323190075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
323290075Sobrien	(match_operator:SI 3 "shiftable_operator"
323390075Sobrien	 [(zero_extend:SI (match_operand:HI 1 "alignable_memory_operand" ""))
323490075Sobrien	  (match_operand:SI 4 "s_register_operand" "")]))
323590075Sobrien   (clobber (match_operand:SI 2 "s_register_operand" ""))]
323690075Sobrien  "TARGET_ARM && (!arm_arch4)"
323790075Sobrien  [(set (match_dup 2) (match_dup 1))
323890075Sobrien   (set (match_dup 0)
323990075Sobrien	(match_op_dup 3
324090075Sobrien	 [(lshiftrt:SI (match_dup 2) (const_int 16)) (match_dup 4)]))]
324190075Sobrien  "
324290075Sobrien  if ((operands[1] = arm_gen_rotated_half_load (operands[1])) == NULL)
324390075Sobrien    FAIL;
324490075Sobrien  "
324590075Sobrien)
324690075Sobrien
324790075Sobrien(define_expand "zero_extendqisi2"
324890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
324990075Sobrien	(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
325090075Sobrien  "TARGET_EITHER"
325190075Sobrien  "
325290075Sobrien  if (GET_CODE (operands[1]) != MEM)
325390075Sobrien    {
325490075Sobrien      if (TARGET_ARM)
325590075Sobrien        {
325690075Sobrien          emit_insn (gen_andsi3 (operands[0],
325790075Sobrien				 gen_lowpart (SImode, operands[1]),
325890075Sobrien			         GEN_INT (255)));
325990075Sobrien        }
326090075Sobrien      else /* TARGET_THUMB */
326190075Sobrien        {
326290075Sobrien          rtx temp = gen_reg_rtx (SImode);
326390075Sobrien	  rtx ops[3];
326490075Sobrien	  
326590075Sobrien          operands[1] = copy_to_mode_reg (QImode, operands[1]);
326690075Sobrien          operands[1] = gen_lowpart (SImode, operands[1]);
326790075Sobrien
326890075Sobrien	  ops[0] = temp;
326990075Sobrien	  ops[1] = operands[1];
327090075Sobrien	  ops[2] = GEN_INT (24);
327190075Sobrien
327290075Sobrien	  emit_insn (gen_rtx_SET (VOIDmode, ops[0],
327390075Sobrien				  gen_rtx_ASHIFT (SImode, ops[1], ops[2])));
327490075Sobrien	  
327590075Sobrien          ops[0] = operands[0];
327690075Sobrien	  ops[1] = temp;
327790075Sobrien	  ops[2] = GEN_INT (24);
327890075Sobrien
327990075Sobrien	  emit_insn (gen_rtx_SET (VOIDmode, ops[0],
328090075Sobrien				  gen_rtx_LSHIFTRT (SImode, ops[1], ops[2])));
328190075Sobrien	}
328290075Sobrien      DONE;
328390075Sobrien    }
328490075Sobrien  "
328590075Sobrien)
328690075Sobrien
328790075Sobrien(define_insn "*thumb_zero_extendqisi2"
328890075Sobrien  [(set (match_operand:SI                 0 "register_operand" "=l")
328990075Sobrien	(zero_extend:SI (match_operand:QI 1 "memory_operand"    "m")))]
329090075Sobrien  "TARGET_THUMB"
329190075Sobrien  "ldrb\\t%0, %1"
329290075Sobrien  [(set_attr "length" "2")
329390075Sobrien   (set_attr "type" "load")
329490075Sobrien   (set_attr "pool_range" "32")]
329590075Sobrien)
329690075Sobrien
329790075Sobrien(define_insn "*arm_zero_extendqisi2"
329890075Sobrien  [(set (match_operand:SI                 0 "s_register_operand" "=r")
329990075Sobrien	(zero_extend:SI (match_operand:QI 1 "memory_operand"      "m")))]
330090075Sobrien  "TARGET_ARM"
330190075Sobrien  "ldr%?b\\t%0, %1\\t%@ zero_extendqisi2"
330290075Sobrien  [(set_attr "type" "load")
330390075Sobrien   (set_attr "predicable" "yes")
330490075Sobrien   (set_attr "pool_range" "4096")
330590075Sobrien   (set_attr "neg_pool_range" "4084")]
330690075Sobrien)
330790075Sobrien
330890075Sobrien(define_split
330990075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
331090075Sobrien	(zero_extend:SI (subreg:QI (match_operand:SI 1 "" "") 0)))
331190075Sobrien   (clobber (match_operand:SI 2 "s_register_operand" ""))]
3312102780Skan  "TARGET_ARM && (GET_CODE (operands[1]) != MEM) && ! BYTES_BIG_ENDIAN"
331390075Sobrien  [(set (match_dup 2) (match_dup 1))
331490075Sobrien   (set (match_dup 0) (and:SI (match_dup 2) (const_int 255)))]
331590075Sobrien  ""
331690075Sobrien)
331790075Sobrien
331890075Sobrien(define_insn "*compareqi_eq0"
331990075Sobrien  [(set (reg:CC_Z CC_REGNUM)
332090075Sobrien	(compare:CC_Z (match_operand:QI 0 "s_register_operand" "r")
332190075Sobrien			 (const_int 0)))]
332290075Sobrien  "TARGET_ARM"
332390075Sobrien  "tst\\t%0, #255"
332490075Sobrien  [(set_attr "conds" "set")]
332590075Sobrien)
332690075Sobrien
332790075Sobrien(define_expand "extendhisi2"
332890075Sobrien  [(set (match_dup 2)
332990075Sobrien	(ashift:SI (match_operand:HI 1 "nonimmediate_operand" "")
333090075Sobrien		   (const_int 16)))
333190075Sobrien   (set (match_operand:SI 0 "s_register_operand" "")
333290075Sobrien	(ashiftrt:SI (match_dup 2)
333390075Sobrien		     (const_int 16)))]
333490075Sobrien  "TARGET_EITHER"
333590075Sobrien  "
333690075Sobrien  {
333790075Sobrien    if (TARGET_ARM && arm_arch4 && GET_CODE (operands[1]) == MEM)
333890075Sobrien      {
333990075Sobrien       /* Note: We do not have to worry about TARGET_MMU_TRAPS
334090075Sobrien	  here because the insn below will generate an LDRH instruction
334190075Sobrien	  rather than an LDR instruction, so we cannot get an unaligned
334290075Sobrien	  word access.  */
334390075Sobrien        emit_insn (gen_rtx_SET (VOIDmode, operands[0],
334490075Sobrien		   gen_rtx_SIGN_EXTEND (SImode, operands[1])));
334590075Sobrien        DONE;
334690075Sobrien      }
334790075Sobrien
334890075Sobrien    if (TARGET_ARM && TARGET_MMU_TRAPS && GET_CODE (operands[1]) == MEM)
334990075Sobrien      {
335090075Sobrien        emit_insn (gen_extendhisi2_mem (operands[0], operands[1]));
335190075Sobrien        DONE;
335290075Sobrien      }
335390075Sobrien    if (!s_register_operand (operands[1], HImode))
335490075Sobrien      operands[1] = copy_to_mode_reg (HImode, operands[1]);
335590075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
335690075Sobrien    operands[2] = gen_reg_rtx (SImode);
335790075Sobrien
335890075Sobrien    if (TARGET_THUMB)
335990075Sobrien      {
336090075Sobrien	rtx ops[3];
336190075Sobrien	
336290075Sobrien	ops[0] = operands[2];
336390075Sobrien	ops[1] = operands[1];
336490075Sobrien	ops[2] = GEN_INT (16);
336590075Sobrien	
336690075Sobrien        emit_insn (gen_rtx_SET (VOIDmode, ops[0],
336790075Sobrien				gen_rtx_ASHIFT (SImode, ops[1], ops[2])));
336890075Sobrien	    
336990075Sobrien	ops[0] = operands[0];
337090075Sobrien	ops[1] = operands[2];
337190075Sobrien	ops[2] = GEN_INT (16);
337290075Sobrien	
337390075Sobrien        emit_insn (gen_rtx_SET (VOIDmode, ops[0],
337490075Sobrien				gen_rtx_ASHIFTRT (SImode, ops[1], ops[2])));
337590075Sobrien	
337690075Sobrien	DONE;
337790075Sobrien      }
337890075Sobrien  }"
337990075Sobrien)
338090075Sobrien
338190075Sobrien(define_insn "*thumb_extendhisi2_insn"
338290075Sobrien  [(set (match_operand:SI                 0 "register_operand" "=l")
338390075Sobrien	(sign_extend:SI (match_operand:HI 1 "memory_operand"    "m")))
338490075Sobrien   (clobber (match_scratch:SI             2                   "=&l"))]
338590075Sobrien  "TARGET_THUMB"
338690075Sobrien  "*
338790075Sobrien  {
338890075Sobrien    rtx ops[4];
338990075Sobrien    rtx mem = XEXP (operands[1], 0);
339090075Sobrien
339190075Sobrien    /* This code used to try to use 'V', and fix the address only if it was
339290075Sobrien       offsettable, but this fails for e.g. REG+48 because 48 is outside the
339390075Sobrien       range of QImode offsets, and offsettable_address_p does a QImode
339490075Sobrien       address check.  */
339590075Sobrien       
339690075Sobrien    if (GET_CODE (mem) == CONST)
339790075Sobrien      mem = XEXP (mem, 0);
339890075Sobrien    
339990075Sobrien    if (GET_CODE (mem) == LABEL_REF)
340090075Sobrien      return \"ldr\\t%0, %1\";
340190075Sobrien    
340290075Sobrien    if (GET_CODE (mem) == PLUS)
340390075Sobrien      {
340490075Sobrien        rtx a = XEXP (mem, 0);
340590075Sobrien        rtx b = XEXP (mem, 1);
340690075Sobrien
340790075Sobrien        if (GET_CODE (a) == LABEL_REF
340890075Sobrien	    && GET_CODE (b) == CONST_INT)
340990075Sobrien          return \"ldr\\t%0, %1\";
341090075Sobrien
341190075Sobrien        if (GET_CODE (b) == REG)
341290075Sobrien          return \"ldrsh\\t%0, %1\";
341390075Sobrien	  
341490075Sobrien        ops[1] = a;
341590075Sobrien        ops[2] = b;
341690075Sobrien      }
341790075Sobrien    else
341890075Sobrien      {
341990075Sobrien        ops[1] = mem;
342090075Sobrien        ops[2] = const0_rtx;
342190075Sobrien      }
342290075Sobrien      
342390075Sobrien    if (GET_CODE (ops[1]) != REG)
342490075Sobrien      {
342590075Sobrien        debug_rtx (ops[1]);
342690075Sobrien        abort ();
342790075Sobrien      }
342890075Sobrien
342990075Sobrien    ops[0] = operands[0];
343090075Sobrien    ops[3] = operands[2];
343190075Sobrien    output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops);
343290075Sobrien    return \"\";
343390075Sobrien  }"
343490075Sobrien  [(set_attr "length" "4")
343590075Sobrien   (set_attr "type" "load")
343690075Sobrien   (set_attr "pool_range" "1020")]
343790075Sobrien)
343890075Sobrien
343990075Sobrien(define_expand "extendhisi2_mem"
344090075Sobrien  [(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" "")))
344190075Sobrien   (set (match_dup 3)
344290075Sobrien	(zero_extend:SI (match_dup 7)))
344390075Sobrien   (set (match_dup 6) (ashift:SI (match_dup 4) (const_int 24)))
344490075Sobrien   (set (match_operand:SI 0 "" "")
344590075Sobrien	(ior:SI (ashiftrt:SI (match_dup 6) (const_int 16)) (match_dup 5)))]
344690075Sobrien  "TARGET_ARM"
344790075Sobrien  "
344890075Sobrien  {
344990075Sobrien    rtx mem1, mem2;
345090075Sobrien    rtx addr = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
345190075Sobrien
345290075Sobrien    mem1 = gen_rtx_MEM (QImode, addr);
345390075Sobrien    MEM_COPY_ATTRIBUTES (mem1, operands[1]);
345490075Sobrien    mem2 = gen_rtx_MEM (QImode, plus_constant (addr, 1));
345590075Sobrien    MEM_COPY_ATTRIBUTES (mem2, operands[1]);
345690075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
345790075Sobrien    operands[1] = mem1;
345890075Sobrien    operands[2] = gen_reg_rtx (SImode);
345990075Sobrien    operands[3] = gen_reg_rtx (SImode);
346090075Sobrien    operands[6] = gen_reg_rtx (SImode);
346190075Sobrien    operands[7] = mem2;
346290075Sobrien
346390075Sobrien    if (BYTES_BIG_ENDIAN)
346490075Sobrien      {
346590075Sobrien	operands[4] = operands[2];
346690075Sobrien	operands[5] = operands[3];
346790075Sobrien      }
346890075Sobrien    else
346990075Sobrien      {
347090075Sobrien	operands[4] = operands[3];
347190075Sobrien	operands[5] = operands[2];
347290075Sobrien      }
347390075Sobrien  }"
347490075Sobrien)
347590075Sobrien
347690075Sobrien(define_insn "*arm_extendhisi_insn"
347790075Sobrien  [(set (match_operand:SI                 0 "s_register_operand" "=r")
347890075Sobrien	(sign_extend:SI (match_operand:HI 1 "memory_operand"      "m")))]
347990075Sobrien  "TARGET_ARM && arm_arch4"
348090075Sobrien  "ldr%?sh\\t%0, %1"
348190075Sobrien  [(set_attr "type" "load")
348290075Sobrien   (set_attr "predicable" "yes")
348390075Sobrien   (set_attr "pool_range" "256")
348490075Sobrien   (set_attr "neg_pool_range" "244")]
348590075Sobrien)
348690075Sobrien
348790075Sobrien(define_split
348890075Sobrien  [(set (match_operand:SI                 0 "s_register_operand" "")
348990075Sobrien	(sign_extend:SI (match_operand:HI 1 "alignable_memory_operand" "")))
349090075Sobrien   (clobber (match_operand:SI             2 "s_register_operand" ""))]
349190075Sobrien  "TARGET_ARM && (!arm_arch4)"
349290075Sobrien  [(set (match_dup 2) (match_dup 1))
349390075Sobrien   (set (match_dup 0) (ashiftrt:SI (match_dup 2) (const_int 16)))]
349490075Sobrien  "
349590075Sobrien  if ((operands[1] = arm_gen_rotated_half_load (operands[1])) == NULL)
349690075Sobrien    FAIL;
349790075Sobrien  "
349890075Sobrien)
349990075Sobrien
350090075Sobrien(define_split
350190075Sobrien  [(set (match_operand:SI                   0 "s_register_operand" "")
350290075Sobrien	(match_operator:SI                  3 "shiftable_operator"
350390075Sobrien	 [(sign_extend:SI (match_operand:HI 1 "alignable_memory_operand" ""))
350490075Sobrien	  (match_operand:SI                 4 "s_register_operand" "")]))
350590075Sobrien   (clobber (match_operand:SI               2 "s_register_operand" ""))]
350690075Sobrien  "TARGET_ARM && (!arm_arch4)"
350790075Sobrien  [(set (match_dup 2) (match_dup 1))
350890075Sobrien   (set (match_dup 0)
350990075Sobrien	(match_op_dup 3
351090075Sobrien	 [(ashiftrt:SI (match_dup 2) (const_int 16)) (match_dup 4)]))]
351190075Sobrien  "if ((operands[1] = arm_gen_rotated_half_load (operands[1])) == NULL)
351290075Sobrien     FAIL;
351390075Sobrien  "
351490075Sobrien)
351590075Sobrien
351690075Sobrien(define_expand "extendqihi2"
351790075Sobrien  [(set (match_dup 2)
351890075Sobrien	(ashift:SI (match_operand:QI 1 "general_operand" "")
351990075Sobrien		   (const_int 24)))
352090075Sobrien   (set (match_operand:HI 0 "s_register_operand" "")
352190075Sobrien	(ashiftrt:SI (match_dup 2)
352290075Sobrien		     (const_int 24)))]
352390075Sobrien  "TARGET_ARM"
352490075Sobrien  "
352590075Sobrien  {
352690075Sobrien    if (arm_arch4 && GET_CODE (operands[1]) == MEM)
352790075Sobrien      {
352890075Sobrien	emit_insn (gen_rtx_SET (VOIDmode,
352990075Sobrien				operands[0],
353090075Sobrien				gen_rtx_SIGN_EXTEND (HImode, operands[1])));
353190075Sobrien	DONE;
353290075Sobrien      }
353390075Sobrien    if (!s_register_operand (operands[1], QImode))
353490075Sobrien      operands[1] = copy_to_mode_reg (QImode, operands[1]);
353590075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
353690075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
353790075Sobrien    operands[2] = gen_reg_rtx (SImode);
353890075Sobrien  }"
353990075Sobrien)
354090075Sobrien
354190075Sobrien; Rather than restricting all byte accesses to memory addresses that ldrsb
354290075Sobrien; can handle, we fix up the ones that ldrsb can't grok with a split.
354390075Sobrien(define_insn "*extendqihi_insn"
354490075Sobrien  [(set (match_operand:HI                 0 "s_register_operand" "=r")
354590075Sobrien	(sign_extend:HI (match_operand:QI 1 "memory_operand"      "m")))]
354690075Sobrien  "TARGET_ARM && arm_arch4"
354790075Sobrien  "*
3548132718Skan  /* If the address is invalid, this will split the instruction into two.  */
354990075Sobrien  if (bad_signed_byte_operand (operands[1], VOIDmode))
355090075Sobrien    return \"#\";
355190075Sobrien  return \"ldr%?sb\\t%0, %1\";
355290075Sobrien  "
355390075Sobrien  [(set_attr "type" "load")
355490075Sobrien   (set_attr "predicable" "yes")
355590075Sobrien   (set_attr "length" "8")
355690075Sobrien   (set_attr "pool_range" "256")
355790075Sobrien   (set_attr "neg_pool_range" "244")]
355890075Sobrien)
355990075Sobrien
356090075Sobrien(define_split
356190075Sobrien  [(set (match_operand:HI 0 "s_register_operand" "")
356290075Sobrien	(sign_extend:HI (match_operand:QI 1 "bad_signed_byte_operand" "")))]
356390075Sobrien  "TARGET_ARM && arm_arch4 && reload_completed"
356490075Sobrien  [(set (match_dup 3) (match_dup 1))
356590075Sobrien   (set (match_dup 0) (sign_extend:HI (match_dup 2)))]
356690075Sobrien  "
356790075Sobrien  {
356890075Sobrien    HOST_WIDE_INT offset;
356990075Sobrien
357090075Sobrien    operands[3] = gen_rtx_REG (SImode, REGNO (operands[0]));
357190075Sobrien    operands[2] = gen_rtx_MEM (QImode, operands[3]);
357290075Sobrien    MEM_COPY_ATTRIBUTES (operands[2], operands[1]);
357390075Sobrien    operands[1] = XEXP (operands[1], 0);
357490075Sobrien    if (GET_CODE (operands[1]) == PLUS
357590075Sobrien	&& GET_CODE (XEXP (operands[1], 1)) == CONST_INT
357690075Sobrien	&& !(const_ok_for_arm (offset = INTVAL (XEXP (operands[1], 1)))
357790075Sobrien	     || const_ok_for_arm (-offset)))
357890075Sobrien      {
357990075Sobrien	HOST_WIDE_INT low = (offset > 0
358090075Sobrien			     ? (offset & 0xff) : -((-offset) & 0xff));
358190075Sobrien	XEXP (operands[2], 0) = plus_constant (operands[3], low);
358290075Sobrien	operands[1] = plus_constant (XEXP (operands[1], 0), offset - low);
358390075Sobrien      }
3584132718Skan    /* Ensure the sum is in correct canonical form.  */
358590075Sobrien    else if (GET_CODE (operands[1]) == PLUS
358690075Sobrien	     && GET_CODE (XEXP (operands[1], 1)) != CONST_INT
358790075Sobrien	     && !s_register_operand (XEXP (operands[1], 1), VOIDmode))
358890075Sobrien      operands[1] = gen_rtx_PLUS (GET_MODE (operands[1]),
358990075Sobrien					   XEXP (operands[1], 1),
359090075Sobrien					   XEXP (operands[1], 0));
359190075Sobrien  }"
359290075Sobrien)
359390075Sobrien
359490075Sobrien(define_expand "extendqisi2"
359590075Sobrien  [(set (match_dup 2)
359690075Sobrien	(ashift:SI (match_operand:QI 1 "general_operand" "")
359790075Sobrien		   (const_int 24)))
359890075Sobrien   (set (match_operand:SI 0 "s_register_operand" "")
359990075Sobrien	(ashiftrt:SI (match_dup 2)
360090075Sobrien		     (const_int 24)))]
360190075Sobrien  "TARGET_EITHER"
360290075Sobrien  "
360390075Sobrien  {
360490075Sobrien    if (TARGET_ARM && arm_arch4 && GET_CODE (operands[1]) == MEM)
360590075Sobrien      {
360690075Sobrien        emit_insn (gen_rtx_SET (VOIDmode,
360790075Sobrien			        operands[0],
360890075Sobrien			        gen_rtx_SIGN_EXTEND (SImode, operands[1])));
360990075Sobrien        DONE;
361090075Sobrien      }
361190075Sobrien    if (!s_register_operand (operands[1], QImode))
361290075Sobrien      operands[1] = copy_to_mode_reg (QImode, operands[1]);
361390075Sobrien    operands[1] = gen_lowpart (SImode, operands[1]);
361490075Sobrien    operands[2] = gen_reg_rtx (SImode);
361590075Sobrien    
361690075Sobrien    if (TARGET_THUMB)
361790075Sobrien      {
361890075Sobrien	rtx ops[3];
361990075Sobrien	
362090075Sobrien	ops[0] = operands[2];
362190075Sobrien	ops[1] = operands[1];
362290075Sobrien	ops[2] = GEN_INT (24);
362390075Sobrien	
362490075Sobrien        emit_insn (gen_rtx_SET (VOIDmode, ops[0],
362590075Sobrien		   gen_rtx_ASHIFT (SImode, ops[1], ops[2])));
362690075Sobrien
362790075Sobrien	ops[0] = operands[0];
362890075Sobrien	ops[1] = operands[2];
362990075Sobrien	ops[2] = GEN_INT (24);
363090075Sobrien	
363190075Sobrien        emit_insn (gen_rtx_SET (VOIDmode, ops[0],
363290075Sobrien		   gen_rtx_ASHIFTRT (SImode, ops[1], ops[2])));
363390075Sobrien	
363490075Sobrien	DONE;
363590075Sobrien      }
363690075Sobrien  }"
363790075Sobrien)
363890075Sobrien
363990075Sobrien; Rather than restricting all byte accesses to memory addresses that ldrsb
364090075Sobrien; can handle, we fix up the ones that ldrsb can't grok with a split.
364190075Sobrien(define_insn "*arm_extendqisi_insn"
364290075Sobrien  [(set (match_operand:SI                 0 "s_register_operand" "=r")
364390075Sobrien	(sign_extend:SI (match_operand:QI 1 "memory_operand"      "m")))]
364490075Sobrien  "TARGET_ARM && arm_arch4"
364590075Sobrien  "*
3646132718Skan  /* If the address is invalid, this will split the instruction into two.  */
364790075Sobrien  if (bad_signed_byte_operand (operands[1], VOIDmode))
364890075Sobrien    return \"#\";
364990075Sobrien  return \"ldr%?sb\\t%0, %1\";
365090075Sobrien  "
365190075Sobrien  [(set_attr "type" "load")
365290075Sobrien   (set_attr "predicable" "yes")
365390075Sobrien   (set_attr "length" "8")
365490075Sobrien   (set_attr "pool_range" "256")
365590075Sobrien   (set_attr "neg_pool_range" "244")]
365690075Sobrien)
365790075Sobrien
365890075Sobrien(define_split
365990075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
366090075Sobrien	(sign_extend:SI (match_operand:QI 1 "bad_signed_byte_operand" "")))]
366190075Sobrien  "TARGET_ARM && arm_arch4 && reload_completed"
366290075Sobrien  [(set (match_dup 0) (match_dup 1))
366390075Sobrien   (set (match_dup 0) (sign_extend:SI (match_dup 2)))]
366490075Sobrien  "
366590075Sobrien  {
366690075Sobrien    HOST_WIDE_INT offset;
366790075Sobrien
366890075Sobrien    operands[2] = gen_rtx_MEM (QImode, operands[0]);
366990075Sobrien    MEM_COPY_ATTRIBUTES (operands[2], operands[1]);
367090075Sobrien    operands[1] = XEXP (operands[1], 0);
367190075Sobrien    if (GET_CODE (operands[1]) == PLUS
367290075Sobrien	&& GET_CODE (XEXP (operands[1], 1)) == CONST_INT
367390075Sobrien	&& !(const_ok_for_arm (offset = INTVAL (XEXP (operands[1], 1)))
367490075Sobrien	     || const_ok_for_arm (-offset)))
367590075Sobrien      {
367690075Sobrien	HOST_WIDE_INT low = (offset > 0
367790075Sobrien			     ? (offset & 0xff) : -((-offset) & 0xff));
367890075Sobrien	XEXP (operands[2], 0) = plus_constant (operands[0], low);
367990075Sobrien	operands[1] = plus_constant (XEXP (operands[1], 0), offset - low);
368090075Sobrien      }
3681132718Skan    /* Ensure the sum is in correct canonical form.  */
368290075Sobrien    else if (GET_CODE (operands[1]) == PLUS
368390075Sobrien	     && GET_CODE (XEXP (operands[1], 1)) != CONST_INT
368490075Sobrien	     && !s_register_operand (XEXP (operands[1], 1), VOIDmode))
368590075Sobrien      operands[1] = gen_rtx_PLUS (GET_MODE (operands[1]),
368690075Sobrien					   XEXP (operands[1], 1),
368790075Sobrien					   XEXP (operands[1], 0));
368890075Sobrien  }"
368990075Sobrien)
369090075Sobrien
369190075Sobrien(define_insn "*thumb_extendqisi2_insn"
369290075Sobrien  [(set (match_operand:SI                 0 "register_operand" "=l,l")
369390075Sobrien	(sign_extend:SI (match_operand:QI 1 "memory_operand"    "V,m")))]
369490075Sobrien  "TARGET_THUMB"
369590075Sobrien  "*
369690075Sobrien  {
369790075Sobrien    rtx ops[3];
369890075Sobrien    rtx mem = XEXP (operands[1], 0);
369990075Sobrien    
370090075Sobrien    if (GET_CODE (mem) == CONST)
370190075Sobrien      mem = XEXP (mem, 0);
370290075Sobrien    
370390075Sobrien    if (GET_CODE (mem) == LABEL_REF)
370490075Sobrien      return \"ldr\\t%0, %1\";
370590075Sobrien
370690075Sobrien    if (GET_CODE (mem) == PLUS
370790075Sobrien        && GET_CODE (XEXP (mem, 0)) == LABEL_REF)
370890075Sobrien      return \"ldr\\t%0, %1\";
370990075Sobrien      
371090075Sobrien    if (which_alternative == 0)
371190075Sobrien      return \"ldrsb\\t%0, %1\";
371290075Sobrien      
371390075Sobrien    ops[0] = operands[0];
371490075Sobrien    
371590075Sobrien    if (GET_CODE (mem) == PLUS)
371690075Sobrien      {
371790075Sobrien        rtx a = XEXP (mem, 0);
371890075Sobrien	rtx b = XEXP (mem, 1);
371990075Sobrien	
372090075Sobrien        ops[1] = a;
372190075Sobrien        ops[2] = b;
372290075Sobrien
372390075Sobrien        if (GET_CODE (a) == REG)
372490075Sobrien	  {
372590075Sobrien	    if (GET_CODE (b) == REG)
372690075Sobrien              output_asm_insn (\"ldrsb\\t%0, [%1, %2]\", ops);
372790075Sobrien            else if (REGNO (a) == REGNO (ops[0]))
372890075Sobrien	      {
372990075Sobrien                output_asm_insn (\"ldrb\\t%0, [%1, %2]\", ops);
373090075Sobrien		output_asm_insn (\"lsl\\t%0, %0, #24\", ops);
373190075Sobrien		output_asm_insn (\"asr\\t%0, %0, #24\", ops);
373290075Sobrien	      }
373390075Sobrien	    else
373490075Sobrien              output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops);
373590075Sobrien	  }
373690075Sobrien        else if (GET_CODE (b) != REG)
373790075Sobrien	  abort ();
373890075Sobrien	else
373990075Sobrien          {
374090075Sobrien            if (REGNO (b) == REGNO (ops[0]))
374190075Sobrien	      {
374290075Sobrien                output_asm_insn (\"ldrb\\t%0, [%2, %1]\", ops);
374390075Sobrien		output_asm_insn (\"lsl\\t%0, %0, #24\", ops);
374490075Sobrien		output_asm_insn (\"asr\\t%0, %0, #24\", ops);
374590075Sobrien	      }
374690075Sobrien	    else
374790075Sobrien              output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops);
374890075Sobrien          }
374990075Sobrien      }
375090075Sobrien    else if (GET_CODE (mem) == REG && REGNO (ops[0]) == REGNO (mem))
375190075Sobrien      {
375290075Sobrien        output_asm_insn (\"ldrb\\t%0, [%0, #0]\", ops);
375390075Sobrien	output_asm_insn (\"lsl\\t%0, %0, #24\", ops);
375490075Sobrien	output_asm_insn (\"asr\\t%0, %0, #24\", ops);
375590075Sobrien      }
375690075Sobrien    else
375790075Sobrien      {
375890075Sobrien        ops[1] = mem;
375990075Sobrien        ops[2] = const0_rtx;
376090075Sobrien	
376190075Sobrien        output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops);
376290075Sobrien      }
376390075Sobrien    return \"\";
376490075Sobrien  }"
376590075Sobrien  [(set_attr "length" "2,6")
376690075Sobrien   (set_attr "type" "load,load")
376790075Sobrien   (set_attr "pool_range" "32,32")]
376890075Sobrien)
376990075Sobrien
3770132718Skan(define_expand "extendsfdf2"
3771132718Skan  [(set (match_operand:DF                  0 "s_register_operand" "")
3772132718Skan	(float_extend:DF (match_operand:SF 1 "s_register_operand"  "")))]
3773132718Skan  "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
3774132718Skan  ""
377590075Sobrien)
377690075Sobrien
377790075Sobrien;; Move insns (including loads and stores)
377890075Sobrien
377990075Sobrien;; XXX Just some ideas about movti.
378090075Sobrien;; I don't think these are a good idea on the arm, there just aren't enough
378190075Sobrien;; registers
378290075Sobrien;;(define_expand "loadti"
378390075Sobrien;;  [(set (match_operand:TI 0 "s_register_operand" "")
378490075Sobrien;;	(mem:TI (match_operand:SI 1 "address_operand" "")))]
378590075Sobrien;;  "" "")
378690075Sobrien
378790075Sobrien;;(define_expand "storeti"
378890075Sobrien;;  [(set (mem:TI (match_operand:TI 0 "address_operand" ""))
378990075Sobrien;;	(match_operand:TI 1 "s_register_operand" ""))]
379090075Sobrien;;  "" "")
379190075Sobrien
379290075Sobrien;;(define_expand "movti"
379390075Sobrien;;  [(set (match_operand:TI 0 "general_operand" "")
379490075Sobrien;;	(match_operand:TI 1 "general_operand" ""))]
379590075Sobrien;;  ""
379690075Sobrien;;  "
379790075Sobrien;;{
379890075Sobrien;;  rtx insn;
379990075Sobrien;;
380090075Sobrien;;  if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
380190075Sobrien;;    operands[1] = copy_to_reg (operands[1]);
380290075Sobrien;;  if (GET_CODE (operands[0]) == MEM)
380390075Sobrien;;    insn = gen_storeti (XEXP (operands[0], 0), operands[1]);
380490075Sobrien;;  else if (GET_CODE (operands[1]) == MEM)
380590075Sobrien;;    insn = gen_loadti (operands[0], XEXP (operands[1], 0));
380690075Sobrien;;  else
380790075Sobrien;;    FAIL;
380890075Sobrien;;
380990075Sobrien;;  emit_insn (insn);
381090075Sobrien;;  DONE;
381190075Sobrien;;}")
381290075Sobrien
3813117395Skan;; Recognize garbage generated above.
381490075Sobrien
381590075Sobrien;;(define_insn ""
381690075Sobrien;;  [(set (match_operand:TI 0 "general_operand" "=r,r,r,<,>,m")
381790075Sobrien;;	(match_operand:TI 1 "general_operand" "<,>,m,r,r,r"))]
381890075Sobrien;;  ""
381990075Sobrien;;  "*
382090075Sobrien;;  {
382190075Sobrien;;    register mem = (which_alternative < 3);
382290075Sobrien;;    register const char *template;
382390075Sobrien;;
382490075Sobrien;;    operands[mem] = XEXP (operands[mem], 0);
382590075Sobrien;;    switch (which_alternative)
382690075Sobrien;;      {
382790075Sobrien;;      case 0: template = \"ldmdb\\t%1!, %M0\"; break;
382890075Sobrien;;      case 1: template = \"ldmia\\t%1!, %M0\"; break;
382990075Sobrien;;      case 2: template = \"ldmia\\t%1, %M0\"; break;
383090075Sobrien;;      case 3: template = \"stmdb\\t%0!, %M1\"; break;
383190075Sobrien;;      case 4: template = \"stmia\\t%0!, %M1\"; break;
383290075Sobrien;;      case 5: template = \"stmia\\t%0, %M1\"; break;
383390075Sobrien;;      }
383490075Sobrien;;    output_asm_insn (template, operands);
383590075Sobrien;;    return \"\";
383690075Sobrien;;  }")
383790075Sobrien
383890075Sobrien(define_expand "movdi"
383990075Sobrien  [(set (match_operand:DI 0 "general_operand" "")
384090075Sobrien	(match_operand:DI 1 "general_operand" ""))]
384190075Sobrien  "TARGET_EITHER"
384290075Sobrien  "
384390075Sobrien  if (TARGET_THUMB)
384490075Sobrien    {
384590075Sobrien      if (!no_new_pseudos)
384690075Sobrien        {
384790075Sobrien          if (GET_CODE (operands[0]) != REG)
384890075Sobrien	    operands[1] = force_reg (DImode, operands[1]);
384990075Sobrien        }
385090075Sobrien    }
385190075Sobrien  "
385290075Sobrien)
385390075Sobrien
385490075Sobrien(define_insn "*arm_movdi"
385590075Sobrien  [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r, r, o<>")
385690075Sobrien	(match_operand:DI 1 "di_operand"              "rIK,mi,r"))]
3857132718Skan  "TARGET_ARM && !TARGET_CIRRUS && ! TARGET_IWMMXT"
385890075Sobrien  "*
385990075Sobrien  return (output_move_double (operands));
386090075Sobrien  "
386190075Sobrien  [(set_attr "length" "8")
386290075Sobrien   (set_attr "type" "*,load,store2")
386390075Sobrien   (set_attr "pool_range" "*,1020,*")
386496263Sobrien   (set_attr "neg_pool_range" "*,1008,*")]
386590075Sobrien)
386690075Sobrien
386790075Sobrien;;; ??? This should have alternatives for constants.
386890075Sobrien;;; ??? This was originally identical to the movdf_insn pattern.
386990075Sobrien;;; ??? The 'i' constraint looks funny, but it should always be replaced by
387090075Sobrien;;; thumb_reorg with a memory reference.
387190075Sobrien(define_insn "*thumb_movdi_insn"
387290075Sobrien  [(set (match_operand:DI 0 "nonimmediate_operand" "=l,l,l,l,>,l, m,*r")
387390075Sobrien	(match_operand:DI 1 "general_operand"      "l, I,J,>,l,mi,l,*r"))]
387490075Sobrien  "TARGET_THUMB
3875132718Skan   && !TARGET_CIRRUS
387690075Sobrien   && (   register_operand (operands[0], DImode)
387790075Sobrien       || register_operand (operands[1], DImode))"
387890075Sobrien  "*
387990075Sobrien  {
388090075Sobrien  switch (which_alternative)
388190075Sobrien    {
388290075Sobrien    default:
388390075Sobrien    case 0:
388490075Sobrien      if (REGNO (operands[1]) == REGNO (operands[0]) + 1)
388590075Sobrien	return \"add\\t%0,  %1,  #0\;add\\t%H0, %H1, #0\";
388690075Sobrien      return   \"add\\t%H0, %H1, #0\;add\\t%0,  %1,  #0\";
388790075Sobrien    case 1:
388890075Sobrien      return \"mov\\t%Q0, %1\;mov\\t%R0, #0\";
388990075Sobrien    case 2:
389090075Sobrien      operands[1] = GEN_INT (- INTVAL (operands[1]));
389190075Sobrien      return \"mov\\t%Q0, %1\;neg\\t%Q0, %Q0\;asr\\t%R0, %Q0, #31\";
389290075Sobrien    case 3:
389390075Sobrien      return \"ldmia\\t%1, {%0, %H0}\";
389490075Sobrien    case 4:
389590075Sobrien      return \"stmia\\t%0, {%1, %H1}\";
389690075Sobrien    case 5:
389790075Sobrien      return thumb_load_double_from_address (operands);
389890075Sobrien    case 6:
389990075Sobrien      operands[2] = gen_rtx (MEM, SImode,
390090075Sobrien			     plus_constant (XEXP (operands[0], 0), 4));
390190075Sobrien      output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands);
390290075Sobrien      return \"\";
390390075Sobrien    case 7:
390490075Sobrien      if (REGNO (operands[1]) == REGNO (operands[0]) + 1)
390590075Sobrien	return \"mov\\t%0, %1\;mov\\t%H0, %H1\";
390690075Sobrien      return \"mov\\t%H0, %H1\;mov\\t%0, %1\";
390790075Sobrien    }
390890075Sobrien  }"
390990075Sobrien  [(set_attr "length" "4,4,6,2,2,6,4,4")
391090075Sobrien   (set_attr "type" "*,*,*,load,store2,load,store2,*")
391190075Sobrien   (set_attr "pool_range" "*,*,*,*,*,1020,*,*")]
391290075Sobrien)
391390075Sobrien
391490075Sobrien(define_expand "movsi"
391590075Sobrien  [(set (match_operand:SI 0 "general_operand" "")
391690075Sobrien        (match_operand:SI 1 "general_operand" ""))]
391790075Sobrien  "TARGET_EITHER"
391890075Sobrien  "
391990075Sobrien  if (TARGET_ARM)
392090075Sobrien    {
3921132718Skan      /* Everything except mem = const or mem = mem can be done easily.  */
392290075Sobrien      if (GET_CODE (operands[0]) == MEM)
392390075Sobrien        operands[1] = force_reg (SImode, operands[1]);
392490075Sobrien      if (GET_CODE (operands[1]) == CONST_INT
392590075Sobrien          && !(const_ok_for_arm (INTVAL (operands[1]))
392690075Sobrien               || const_ok_for_arm (~INTVAL (operands[1]))))
392790075Sobrien        {
392890075Sobrien           arm_split_constant (SET, SImode, INTVAL (operands[1]), operands[0],
392990075Sobrien		    	      NULL_RTX,
393090075Sobrien			      (no_new_pseudos ? 0
393190075Sobrien			       : preserve_subexpressions_p ()));
393290075Sobrien          DONE;
393390075Sobrien        }
393490075Sobrien    }
3935132718Skan  else /* TARGET_THUMB....  */
393690075Sobrien    {
393790075Sobrien      if (!no_new_pseudos)
393890075Sobrien        {
393990075Sobrien          if (GET_CODE (operands[0]) != REG)
394090075Sobrien	    operands[1] = force_reg (SImode, operands[1]);
394190075Sobrien        }
394290075Sobrien    }
394390075Sobrien    
394490075Sobrien  if (flag_pic
394590075Sobrien      && (CONSTANT_P (operands[1])
394690075Sobrien	 || symbol_mentioned_p (operands[1])
394790075Sobrien	 || label_mentioned_p (operands[1])))
394890075Sobrien    operands[1] = legitimize_pic_address (operands[1], SImode,
394990075Sobrien					  (no_new_pseudos ? operands[0] : 0));
395090075Sobrien  "
395190075Sobrien)
395290075Sobrien
395390075Sobrien(define_insn "*arm_movsi_insn"
395490075Sobrien  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r, m")
395590075Sobrien	(match_operand:SI 1 "general_operand"      "rI,K,mi,r"))]
3956132718Skan  "TARGET_ARM && ! TARGET_IWMMXT
395790075Sobrien   && (   register_operand (operands[0], SImode)
395890075Sobrien       || register_operand (operands[1], SImode))"
395990075Sobrien  "@
396090075Sobrien   mov%?\\t%0, %1
396190075Sobrien   mvn%?\\t%0, #%B1
396290075Sobrien   ldr%?\\t%0, %1
396390075Sobrien   str%?\\t%1, %0"
396490075Sobrien  [(set_attr "type" "*,*,load,store1")
396590075Sobrien   (set_attr "predicable" "yes")
396690075Sobrien   (set_attr "pool_range" "*,*,4096,*")
396790075Sobrien   (set_attr "neg_pool_range" "*,*,4084,*")]
396890075Sobrien)
396990075Sobrien
397090075Sobrien(define_split
397190075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
397290075Sobrien	(match_operand:SI 1 "const_int_operand" ""))]
397390075Sobrien  "TARGET_ARM
397490075Sobrien  && (!(const_ok_for_arm (INTVAL (operands[1]))
397590075Sobrien        || const_ok_for_arm (~INTVAL (operands[1]))))"
397690075Sobrien  [(clobber (const_int 0))]
397790075Sobrien  "
397890075Sobrien  arm_split_constant (SET, SImode, INTVAL (operands[1]), operands[0],
397990075Sobrien		      NULL_RTX, 0);
398090075Sobrien  DONE;
398190075Sobrien  "
398290075Sobrien)
398390075Sobrien
398490075Sobrien(define_insn "*thumb_movsi_insn"
398590075Sobrien  [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l, m,*lh")
398690075Sobrien	(match_operand:SI 1 "general_operand"      "l, I,J,K,>,l,mi,l,*lh"))]
398790075Sobrien  "TARGET_THUMB
398890075Sobrien   && (   register_operand (operands[0], SImode) 
398990075Sobrien       || register_operand (operands[1], SImode))"
399090075Sobrien  "@
399190075Sobrien   mov	%0, %1
399290075Sobrien   mov	%0, %1
399390075Sobrien   #
399490075Sobrien   #
399590075Sobrien   ldmia\\t%1, {%0}
399690075Sobrien   stmia\\t%0, {%1}
399790075Sobrien   ldr\\t%0, %1
399890075Sobrien   str\\t%1, %0
399990075Sobrien   mov\\t%0, %1"
400090075Sobrien  [(set_attr "length" "2,2,4,4,2,2,2,2,2")
400190075Sobrien   (set_attr "type" "*,*,*,*,load,store1,load,store1,*")
400290075Sobrien   (set_attr "pool_range" "*,*,*,*,*,*,1020,*,*")]
400390075Sobrien)
400490075Sobrien
400590075Sobrien(define_split 
400690075Sobrien  [(set (match_operand:SI 0 "register_operand" "")
400790075Sobrien	(match_operand:SI 1 "const_int_operand" ""))]
400890075Sobrien  "TARGET_THUMB && CONST_OK_FOR_THUMB_LETTER (INTVAL (operands[1]), 'J')"
400990075Sobrien  [(set (match_dup 0) (match_dup 1))
401090075Sobrien   (set (match_dup 0) (neg:SI (match_dup 0)))]
401190075Sobrien  "operands[1] = GEN_INT (- INTVAL (operands[1]));"
401290075Sobrien)
401390075Sobrien
401490075Sobrien(define_split 
401590075Sobrien  [(set (match_operand:SI 0 "register_operand" "")
401690075Sobrien	(match_operand:SI 1 "const_int_operand" ""))]
401790075Sobrien  "TARGET_THUMB && CONST_OK_FOR_THUMB_LETTER (INTVAL (operands[1]), 'K')"
401890075Sobrien  [(set (match_dup 0) (match_dup 1))
401990075Sobrien   (set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))]
402090075Sobrien  "
402190075Sobrien  {
402290075Sobrien    unsigned HOST_WIDE_INT val = INTVAL (operands[1]);
402390075Sobrien    unsigned HOST_WIDE_INT mask = 0xff;
402490075Sobrien    int i;
402590075Sobrien    
402690075Sobrien    for (i = 0; i < 25; i++)
402790075Sobrien      if ((val & (mask << i)) == val)
402890075Sobrien        break;
402990075Sobrien
4030117395Skan    /* Shouldn't happen, but we don't want to split if the shift is zero.  */
403190075Sobrien    if (i == 0)
403290075Sobrien      FAIL;
403390075Sobrien
403490075Sobrien    operands[1] = GEN_INT (val >> i);
403590075Sobrien    operands[2] = GEN_INT (i);
403690075Sobrien  }"
403790075Sobrien)
403890075Sobrien
403990075Sobrien;; When generating pic, we need to load the symbol offset into a register.
404090075Sobrien;; So that the optimizer does not confuse this with a normal symbol load
404190075Sobrien;; we use an unspec.  The offset will be loaded from a constant pool entry,
404290075Sobrien;; since that is the only type of relocation we can use.
404390075Sobrien
404490075Sobrien;; The rather odd constraints on the following are to force reload to leave
404590075Sobrien;; the insn alone, and to force the minipool generation pass to then move
404690075Sobrien;; the GOT symbol to memory.
404790075Sobrien
404890075Sobrien(define_insn "pic_load_addr_arm"
404990075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
405090075Sobrien	(unspec:SI [(match_operand:SI 1 "" "mX")] UNSPEC_PIC_SYM))]
405190075Sobrien  "TARGET_ARM && flag_pic"
405290075Sobrien  "ldr%?\\t%0, %1"
405390075Sobrien  [(set_attr "type" "load")
405490075Sobrien   (set (attr "pool_range")     (const_int 4096))
405590075Sobrien   (set (attr "neg_pool_range") (const_int 4084))]
405690075Sobrien)
405790075Sobrien
405890075Sobrien(define_insn "pic_load_addr_thumb"
405990075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=l")
406090075Sobrien	(unspec:SI [(match_operand:SI 1 "" "mX")] UNSPEC_PIC_SYM))]
406190075Sobrien  "TARGET_THUMB && flag_pic"
406290075Sobrien  "ldr\\t%0, %1"
406390075Sobrien  [(set_attr "type" "load")
406490075Sobrien   (set (attr "pool_range") (const_int 1024))]
406590075Sobrien)
406690075Sobrien
406790075Sobrien;; This variant is used for AOF assembly, since it needs to mention the
406890075Sobrien;; pic register in the rtl.
406990075Sobrien(define_expand "pic_load_addr_based"
4070132718Skan  [(set (match_operand:SI 0 "s_register_operand" "")
407190075Sobrien	(unspec:SI [(match_operand 1 "" "") (match_dup 2)] UNSPEC_PIC_SYM))]
407290075Sobrien  "TARGET_ARM && flag_pic"
407390075Sobrien  "operands[2] = pic_offset_table_rtx;"
407490075Sobrien)
407590075Sobrien
407690075Sobrien(define_insn "*pic_load_addr_based_insn"
407790075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
407890075Sobrien	(unspec:SI [(match_operand 1 "" "")
407990075Sobrien		    (match_operand 2 "s_register_operand" "r")]
408090075Sobrien		   UNSPEC_PIC_SYM))]
408190075Sobrien  "TARGET_EITHER && flag_pic && operands[2] == pic_offset_table_rtx"
408290075Sobrien  "*
408390075Sobrien#ifdef AOF_ASSEMBLER
408490075Sobrien  operands[1] = aof_pic_entry (operands[1]);
408590075Sobrien#endif
408690075Sobrien  output_asm_insn (\"ldr%?\\t%0, %a1\", operands);
408790075Sobrien  return \"\";
408890075Sobrien  "
408990075Sobrien  [(set_attr "type" "load")
409090075Sobrien   (set (attr "pool_range")
409190075Sobrien	(if_then_else (eq_attr "is_thumb" "yes")
409290075Sobrien		      (const_int 1024)
409390075Sobrien		      (const_int 4096)))
409490075Sobrien   (set (attr "neg_pool_range")
409590075Sobrien	(if_then_else (eq_attr "is_thumb" "yes")
409690075Sobrien		      (const_int 0)
409790075Sobrien		      (const_int 4084)))]
409890075Sobrien)
409990075Sobrien
410090075Sobrien(define_insn "pic_add_dot_plus_four"
410190075Sobrien  [(set (match_operand:SI 0 "register_operand" "+r")
4102117395Skan	(unspec:SI [(plus:SI (match_dup 0)
4103117395Skan			     (const (plus:SI (pc) (const_int 4))))]
4104117395Skan		   UNSPEC_PIC_BASE))
410590075Sobrien   (use (label_ref (match_operand 1 "" "")))]
410690075Sobrien  "TARGET_THUMB && flag_pic"
410790075Sobrien  "*
4108132718Skan  (*targetm.asm_out.internal_label) (asm_out_file, \"L\",
410990075Sobrien			     CODE_LABEL_NUMBER (operands[1]));
411090075Sobrien  return \"add\\t%0, %|pc\";
411190075Sobrien  "
411290075Sobrien  [(set_attr "length" "2")]
411390075Sobrien)
411490075Sobrien
411590075Sobrien(define_insn "pic_add_dot_plus_eight"
411690075Sobrien  [(set (match_operand:SI 0 "register_operand" "+r")
4117117395Skan	(unspec:SI [(plus:SI (match_dup 0)
4118117395Skan			     (const (plus:SI (pc) (const_int 8))))]
4119117395Skan		   UNSPEC_PIC_BASE))
412090075Sobrien   (use (label_ref (match_operand 1 "" "")))]
412190075Sobrien  "TARGET_ARM && flag_pic"
412290075Sobrien  "*
4123132718Skan    (*targetm.asm_out.internal_label) (asm_out_file, \"L\",
412490075Sobrien			       CODE_LABEL_NUMBER (operands[1]));
412590075Sobrien    return \"add%?\\t%0, %|pc, %0\";
412690075Sobrien  "
412790075Sobrien  [(set_attr "predicable" "yes")]
412890075Sobrien)
412990075Sobrien
413090075Sobrien(define_expand "builtin_setjmp_receiver"
413190075Sobrien  [(label_ref (match_operand 0 "" ""))]
413290075Sobrien  "flag_pic"
413390075Sobrien  "
413490075Sobrien{
413590075Sobrien  arm_finalize_pic (0);
413690075Sobrien  DONE;
413790075Sobrien}")
413890075Sobrien
413990075Sobrien;; If copying one reg to another we can set the condition codes according to
414090075Sobrien;; its value.  Such a move is common after a return from subroutine and the
414190075Sobrien;; result is being tested against zero.
414290075Sobrien
414390075Sobrien(define_insn "*movsi_compare0"
414490075Sobrien  [(set (reg:CC CC_REGNUM)
414590075Sobrien	(compare:CC (match_operand:SI 1 "s_register_operand" "0,r")
414690075Sobrien		    (const_int 0)))
414790075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r,r")
414890075Sobrien	(match_dup 1))]
414990075Sobrien  "TARGET_ARM"
415090075Sobrien  "@
415190075Sobrien   cmp%?\\t%0, #0
415290075Sobrien   sub%?s\\t%0, %1, #0"
415390075Sobrien  [(set_attr "conds" "set")]
415490075Sobrien)
415590075Sobrien
415690075Sobrien;; Subroutine to store a half word from a register into memory.
415790075Sobrien;; Operand 0 is the source register (HImode)
415890075Sobrien;; Operand 1 is the destination address in a register (SImode)
415990075Sobrien
416090075Sobrien;; In both this routine and the next, we must be careful not to spill
416190075Sobrien;; a memory address of reg+large_const into a separate PLUS insn, since this
416290075Sobrien;; can generate unrecognizable rtl.
416390075Sobrien
416490075Sobrien(define_expand "storehi"
416590075Sobrien  [;; store the low byte
416690075Sobrien   (set (match_operand 1 "" "") (match_dup 3))
416790075Sobrien   ;; extract the high byte
416890075Sobrien   (set (match_dup 2)
416990075Sobrien	(ashiftrt:SI (match_operand 0 "" "") (const_int 8)))
417090075Sobrien   ;; store the high byte
4171132718Skan   (set (match_dup 4) (match_dup 5))]
417290075Sobrien  "TARGET_ARM"
417390075Sobrien  "
417490075Sobrien  {
417590075Sobrien    rtx op1 = operands[1];
417690075Sobrien    rtx addr = XEXP (op1, 0);
417790075Sobrien    enum rtx_code code = GET_CODE (addr);
417890075Sobrien
417990075Sobrien    if ((code == PLUS && GET_CODE (XEXP (addr, 1)) != CONST_INT)
418090075Sobrien	|| code == MINUS)
418190075Sobrien      op1 = replace_equiv_address (operands[1], force_reg (SImode, addr));
418290075Sobrien
418390075Sobrien    operands[4] = adjust_address (op1, QImode, 1);
418490075Sobrien    operands[1] = adjust_address (operands[1], QImode, 0);
418590075Sobrien    operands[3] = gen_lowpart (QImode, operands[0]);
418690075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
4187132718Skan    operands[2] = gen_reg_rtx (SImode);
4188132718Skan    operands[5] = gen_lowpart (QImode, operands[2]);
418990075Sobrien  }"
419090075Sobrien)
419190075Sobrien
419290075Sobrien(define_expand "storehi_bigend"
419390075Sobrien  [(set (match_dup 4) (match_dup 3))
419490075Sobrien   (set (match_dup 2)
419590075Sobrien	(ashiftrt:SI (match_operand 0 "" "") (const_int 8)))
4196132718Skan   (set (match_operand 1 "" "")	(match_dup 5))]
419790075Sobrien  "TARGET_ARM"
419890075Sobrien  "
419990075Sobrien  {
420090075Sobrien    rtx op1 = operands[1];
420190075Sobrien    rtx addr = XEXP (op1, 0);
420290075Sobrien    enum rtx_code code = GET_CODE (addr);
420390075Sobrien
420490075Sobrien    if ((code == PLUS && GET_CODE (XEXP (addr, 1)) != CONST_INT)
420590075Sobrien	|| code == MINUS)
420690075Sobrien      op1 = replace_equiv_address (op1, force_reg (SImode, addr));
420790075Sobrien
420890075Sobrien    operands[4] = adjust_address (op1, QImode, 1);
420990075Sobrien    operands[1] = adjust_address (operands[1], QImode, 0);
421090075Sobrien    operands[3] = gen_lowpart (QImode, operands[0]);
421190075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
421290075Sobrien    operands[2] = gen_reg_rtx (SImode);
4213132718Skan    operands[5] = gen_lowpart (QImode, operands[2]);
421490075Sobrien  }"
421590075Sobrien)
421690075Sobrien
421790075Sobrien;; Subroutine to store a half word integer constant into memory.
421890075Sobrien(define_expand "storeinthi"
421990075Sobrien  [(set (match_operand 0 "" "")
4220132718Skan	(match_operand 1 "" ""))
4221102780Skan   (set (match_dup 3) (match_dup 2))]
422290075Sobrien  "TARGET_ARM"
422390075Sobrien  "
422490075Sobrien  {
422590075Sobrien    HOST_WIDE_INT value = INTVAL (operands[1]);
422690075Sobrien    rtx addr = XEXP (operands[0], 0);
422790075Sobrien    rtx op0 = operands[0];
422890075Sobrien    enum rtx_code code = GET_CODE (addr);
422990075Sobrien
423090075Sobrien    if ((code == PLUS && GET_CODE (XEXP (addr, 1)) != CONST_INT)
423190075Sobrien	|| code == MINUS)
423290075Sobrien      op0 = replace_equiv_address (op0, force_reg (SImode, addr));
423390075Sobrien
423490075Sobrien    operands[1] = gen_reg_rtx (SImode);
423590075Sobrien    if (BYTES_BIG_ENDIAN)
423690075Sobrien      {
423790075Sobrien	emit_insn (gen_movsi (operands[1], GEN_INT ((value >> 8) & 255)));
423890075Sobrien	if ((value & 255) == ((value >> 8) & 255))
423990075Sobrien	  operands[2] = operands[1];
424090075Sobrien	else
424190075Sobrien	  {
424290075Sobrien	    operands[2] = gen_reg_rtx (SImode);
424390075Sobrien	    emit_insn (gen_movsi (operands[2], GEN_INT (value & 255)));
424490075Sobrien	  }
424590075Sobrien      }
424690075Sobrien    else
424790075Sobrien      {
424890075Sobrien	emit_insn (gen_movsi (operands[1], GEN_INT (value & 255)));
424990075Sobrien	if ((value & 255) == ((value >> 8) & 255))
425090075Sobrien	  operands[2] = operands[1];
425190075Sobrien	else
425290075Sobrien	  {
425390075Sobrien	    operands[2] = gen_reg_rtx (SImode);
425490075Sobrien	    emit_insn (gen_movsi (operands[2], GEN_INT ((value >> 8) & 255)));
425590075Sobrien	  }
425690075Sobrien      }
425790075Sobrien
425890075Sobrien    operands[3] = adjust_address (op0, QImode, 1);
425990075Sobrien    operands[0] = adjust_address (operands[0], QImode, 0);
4260102780Skan    operands[2] = gen_lowpart (QImode, operands[2]);
4261132718Skan    operands[1] = gen_lowpart (QImode, operands[1]);
426290075Sobrien  }"
426390075Sobrien)
426490075Sobrien
426590075Sobrien(define_expand "storehi_single_op"
426690075Sobrien  [(set (match_operand:HI 0 "memory_operand" "")
426790075Sobrien	(match_operand:HI 1 "general_operand" ""))]
426890075Sobrien  "TARGET_ARM && arm_arch4"
426990075Sobrien  "
427090075Sobrien  if (!s_register_operand (operands[1], HImode))
427190075Sobrien    operands[1] = copy_to_mode_reg (HImode, operands[1]);
427290075Sobrien  "
427390075Sobrien)
427490075Sobrien
427590075Sobrien(define_expand "movhi"
427690075Sobrien  [(set (match_operand:HI 0 "general_operand" "")
427790075Sobrien	(match_operand:HI 1 "general_operand" ""))]
427890075Sobrien  "TARGET_EITHER"
427990075Sobrien  "
428090075Sobrien  if (TARGET_ARM)
428190075Sobrien    {
428290075Sobrien      if (!no_new_pseudos)
428390075Sobrien        {
428490075Sobrien          if (GET_CODE (operands[0]) == MEM)
428590075Sobrien	    {
428690075Sobrien	      if (arm_arch4)
428790075Sobrien	        {
428890075Sobrien	          emit_insn (gen_storehi_single_op (operands[0], operands[1]));
428990075Sobrien	          DONE;
429090075Sobrien	        }
429190075Sobrien	      if (GET_CODE (operands[1]) == CONST_INT)
429290075Sobrien	        emit_insn (gen_storeinthi (operands[0], operands[1]));
429390075Sobrien	      else
429490075Sobrien	        {
429590075Sobrien	          if (GET_CODE (operands[1]) == MEM)
429690075Sobrien		    operands[1] = force_reg (HImode, operands[1]);
429790075Sobrien	          if (BYTES_BIG_ENDIAN)
429890075Sobrien		    emit_insn (gen_storehi_bigend (operands[1], operands[0]));
429990075Sobrien	          else
430090075Sobrien		   emit_insn (gen_storehi (operands[1], operands[0]));
430190075Sobrien	        }
430290075Sobrien	      DONE;
430390075Sobrien	    }
430490075Sobrien          /* Sign extend a constant, and keep it in an SImode reg.  */
430590075Sobrien          else if (GET_CODE (operands[1]) == CONST_INT)
430690075Sobrien	    {
430790075Sobrien	      rtx reg = gen_reg_rtx (SImode);
430890075Sobrien	      HOST_WIDE_INT val = INTVAL (operands[1]) & 0xffff;
430990075Sobrien
431090075Sobrien	      /* If the constant is already valid, leave it alone.  */
431190075Sobrien	      if (!const_ok_for_arm (val))
431290075Sobrien	        {
431390075Sobrien	          /* If setting all the top bits will make the constant 
431490075Sobrien		     loadable in a single instruction, then set them.  
431590075Sobrien		     Otherwise, sign extend the number.  */
431690075Sobrien
431790075Sobrien	          if (const_ok_for_arm (~(val | ~0xffff)))
431890075Sobrien		    val |= ~0xffff;
431990075Sobrien	          else if (val & 0x8000)
432090075Sobrien		    val |= ~0xffff;
432190075Sobrien	        }
432290075Sobrien
432390075Sobrien	      emit_insn (gen_movsi (reg, GEN_INT (val)));
4324102780Skan	      operands[1] = gen_lowpart (HImode, reg);
432590075Sobrien	    }
4326117395Skan	  else if (arm_arch4 && !no_new_pseudos && optimize > 0
4327117395Skan		   && GET_CODE (operands[1]) == MEM)
4328117395Skan	    {
4329117395Skan	      rtx reg = gen_reg_rtx (SImode);
4330117395Skan
4331117395Skan	      emit_insn (gen_zero_extendhisi2 (reg, operands[1]));
4332117395Skan	      operands[1] = gen_lowpart (HImode, reg);
4333117395Skan	    }
433490075Sobrien          else if (!arm_arch4)
433590075Sobrien	    {
433690075Sobrien	     /* Note: We do not have to worry about TARGET_MMU_TRAPS
433790075Sobrien	        for v4 and up architectures because LDRH instructions will
433890075Sobrien	        be used to access the HI values, and these cannot generate
433990075Sobrien	        unaligned word access faults in the MMU.  */
434090075Sobrien	      if (GET_CODE (operands[1]) == MEM)
434190075Sobrien	        {
434290075Sobrien	          if (TARGET_MMU_TRAPS)
434390075Sobrien		    {
434490075Sobrien		      rtx base;
434590075Sobrien		      rtx offset = const0_rtx;
434690075Sobrien		      rtx reg = gen_reg_rtx (SImode);
434790075Sobrien
434890075Sobrien		      if ((GET_CODE (base = XEXP (operands[1], 0)) == REG
434990075Sobrien		           || (GET_CODE (base) == PLUS
435090075Sobrien			       && (GET_CODE (offset = XEXP (base, 1))
435190075Sobrien				   == CONST_INT)
435290075Sobrien                               && ((INTVAL(offset) & 1) != 1)
435390075Sobrien			       && GET_CODE (base = XEXP (base, 0)) == REG))
435490075Sobrien		          && REGNO_POINTER_ALIGN (REGNO (base)) >= 32)
435590075Sobrien		        {
435690075Sobrien		          HOST_WIDE_INT new_offset = INTVAL (offset) & ~3;
435790075Sobrien		          rtx new;
435890075Sobrien
435990075Sobrien		          new = gen_rtx_MEM (SImode,
436090075Sobrien				   	     plus_constant (base, new_offset));
436190075Sobrien	                  MEM_COPY_ATTRIBUTES (new, operands[1]);
436290075Sobrien		          emit_insn (gen_movsi (reg, new));
436390075Sobrien		          if (((INTVAL (offset) & 2) != 0)
436490075Sobrien			      ^ (BYTES_BIG_ENDIAN ? 1 : 0))
436590075Sobrien			    {
436690075Sobrien			      rtx reg2 = gen_reg_rtx (SImode);
436790075Sobrien
436890075Sobrien			      emit_insn (gen_lshrsi3 (reg2, reg,
436990075Sobrien					 GEN_INT (16)));
437090075Sobrien			      reg = reg2;
437190075Sobrien			    }
437290075Sobrien		        }
437390075Sobrien		      else
437490075Sobrien		        emit_insn (gen_movhi_bytes (reg, operands[1]));
437590075Sobrien
437690075Sobrien		      operands[1] = gen_lowpart (HImode, reg);
437790075Sobrien		    }
437890075Sobrien	          else if (BYTES_BIG_ENDIAN)
437990075Sobrien		    {
438090075Sobrien		      rtx base;
438190075Sobrien		      rtx offset = const0_rtx;
438290075Sobrien
438390075Sobrien		      if ((GET_CODE (base = XEXP (operands[1], 0)) == REG
438490075Sobrien		           || (GET_CODE (base) == PLUS
438590075Sobrien			      && (GET_CODE (offset = XEXP (base, 1))
438690075Sobrien				  == CONST_INT)
438790075Sobrien			      && GET_CODE (base = XEXP (base, 0)) == REG))
438890075Sobrien		          && REGNO_POINTER_ALIGN (REGNO (base)) >= 32)
438990075Sobrien		        {
439090075Sobrien		          rtx reg = gen_reg_rtx (SImode);
439190075Sobrien		          rtx new;
439290075Sobrien
439390075Sobrien		          if ((INTVAL (offset) & 2) == 2)
439490075Sobrien			    {
439590075Sobrien			      HOST_WIDE_INT new_offset = INTVAL (offset) ^ 2;
439690075Sobrien			      new = gen_rtx_MEM (SImode,
439790075Sobrien				  	         plus_constant (base,
439890075Sobrien								new_offset));
439990075Sobrien                              MEM_COPY_ATTRIBUTES (new, operands[1]);
440090075Sobrien			      emit_insn (gen_movsi (reg, new));
440190075Sobrien			    }
440290075Sobrien		          else
440390075Sobrien			    {
440490075Sobrien			      new = gen_rtx_MEM (SImode,
440590075Sobrien						 XEXP (operands[1], 0));
440690075Sobrien	                      MEM_COPY_ATTRIBUTES (new, operands[1]);
440790075Sobrien			      emit_insn (gen_rotated_loadsi (reg, new));
440890075Sobrien			    }
440990075Sobrien
441090075Sobrien		          operands[1] = gen_lowpart (HImode, reg);
441190075Sobrien		        }
441290075Sobrien		      else
441390075Sobrien		        {
441490075Sobrien		          emit_insn (gen_movhi_bigend (operands[0],
441590075Sobrien						       operands[1]));
441690075Sobrien		          DONE;
441790075Sobrien		        }
441890075Sobrien		    }
441990075Sobrien	       }
442090075Sobrien	   }
442190075Sobrien        }
4422132718Skan      /* Handle loading a large integer during reload.  */
442390075Sobrien      else if (GET_CODE (operands[1]) == CONST_INT
442490075Sobrien	       && !const_ok_for_arm (INTVAL (operands[1]))
442590075Sobrien	       && !const_ok_for_arm (~INTVAL (operands[1])))
442690075Sobrien        {
442790075Sobrien          /* Writing a constant to memory needs a scratch, which should
442890075Sobrien	     be handled with SECONDARY_RELOADs.  */
442990075Sobrien          if (GET_CODE (operands[0]) != REG)
443090075Sobrien	    abort ();
443190075Sobrien
443290075Sobrien          operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0);
443390075Sobrien          emit_insn (gen_movsi (operands[0], operands[1]));
443490075Sobrien          DONE;
443590075Sobrien       }
443690075Sobrien    }
443790075Sobrien  else /* TARGET_THUMB */
443890075Sobrien    {
443990075Sobrien      if (!no_new_pseudos)
444090075Sobrien        {
444190075Sobrien          if (GET_CODE (operands[0]) != REG)
444290075Sobrien	    operands[1] = force_reg (HImode, operands[1]);
444390075Sobrien
444490075Sobrien          /* ??? We shouldn't really get invalid addresses here, but this can
444590075Sobrien	     happen if we are passed a SP (never OK for HImode/QImode) or 
444690075Sobrien	     virtual register (rejected by GO_IF_LEGITIMATE_ADDRESS for 
444790075Sobrien	     HImode/QImode) relative address.  */
444890075Sobrien          /* ??? This should perhaps be fixed elsewhere, for instance, in
444990075Sobrien	     fixup_stack_1, by checking for other kinds of invalid addresses,
445090075Sobrien	     e.g. a bare reference to a virtual register.  This may confuse the
445190075Sobrien	     alpha though, which must handle this case differently.  */
445290075Sobrien          if (GET_CODE (operands[0]) == MEM
445390075Sobrien	      && !memory_address_p (GET_MODE (operands[0]),
445490075Sobrien				    XEXP (operands[0], 0)))
445590075Sobrien	    operands[0]
445690075Sobrien	      = replace_equiv_address (operands[0],
445790075Sobrien				       copy_to_reg (XEXP (operands[0], 0)));
445890075Sobrien   
445990075Sobrien          if (GET_CODE (operands[1]) == MEM
446090075Sobrien	      && !memory_address_p (GET_MODE (operands[1]),
446190075Sobrien				    XEXP (operands[1], 0)))
446290075Sobrien	    operands[1]
446390075Sobrien	      = replace_equiv_address (operands[1],
446490075Sobrien				       copy_to_reg (XEXP (operands[1], 0)));
446590075Sobrien        }
4466132718Skan      /* Handle loading a large integer during reload.  */
446790075Sobrien      else if (GET_CODE (operands[1]) == CONST_INT
446890075Sobrien	        && !CONST_OK_FOR_THUMB_LETTER (INTVAL (operands[1]), 'I'))
446990075Sobrien        {
447090075Sobrien          /* Writing a constant to memory needs a scratch, which should
447190075Sobrien	     be handled with SECONDARY_RELOADs.  */
447290075Sobrien          if (GET_CODE (operands[0]) != REG)
447390075Sobrien	    abort ();
447490075Sobrien
447590075Sobrien          operands[0] = gen_rtx (SUBREG, SImode, operands[0], 0);
447690075Sobrien          emit_insn (gen_movsi (operands[0], operands[1]));
447790075Sobrien          DONE;
447890075Sobrien        }
447990075Sobrien    }
448090075Sobrien  "
448190075Sobrien)
448290075Sobrien
448390075Sobrien(define_insn "*thumb_movhi_insn"
4484132718Skan  [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l")
4485132718Skan	(match_operand:HI 1 "general_operand"       "l,m,l,*h,*r,I"))]
448690075Sobrien  "TARGET_THUMB
448790075Sobrien   && (   register_operand (operands[0], HImode)
448890075Sobrien       || register_operand (operands[1], HImode))"
448990075Sobrien  "*
449090075Sobrien  switch (which_alternative)
449190075Sobrien    {
449290075Sobrien    case 0: return \"add	%0, %1, #0\";
449390075Sobrien    case 2: return \"strh	%1, %0\";
449490075Sobrien    case 3: return \"mov	%0, %1\";
449590075Sobrien    case 4: return \"mov	%0, %1\";
449690075Sobrien    case 5: return \"mov	%0, %1\";
449790075Sobrien    default: abort ();
449890075Sobrien    case 1:
449990075Sobrien      /* The stack pointer can end up being taken as an index register.
450090075Sobrien          Catch this case here and deal with it.  */
450190075Sobrien      if (GET_CODE (XEXP (operands[1], 0)) == PLUS
450290075Sobrien	  && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == REG
450390075Sobrien	  && REGNO    (XEXP (XEXP (operands[1], 0), 0)) == SP_REGNUM)
450490075Sobrien        {
450590075Sobrien	  rtx ops[2];
450690075Sobrien          ops[0] = operands[0];
450790075Sobrien          ops[1] = XEXP (XEXP (operands[1], 0), 0);
450890075Sobrien      
450990075Sobrien          output_asm_insn (\"mov	%0, %1\", ops);
451090075Sobrien
451190075Sobrien          XEXP (XEXP (operands[1], 0), 0) = operands[0];
451290075Sobrien    
451390075Sobrien	}
451490075Sobrien      return \"ldrh	%0, %1\";
451590075Sobrien    }"
451690075Sobrien  [(set_attr "length" "2,4,2,2,2,2")
4517132718Skan   (set_attr "type" "*,load,store1,*,*,*")]
451890075Sobrien)
451990075Sobrien
452090075Sobrien
452190075Sobrien(define_insn "rotated_loadsi"
452290075Sobrien  [(set (match_operand:SI            0 "s_register_operand"        "=r")
452390075Sobrien	(rotate:SI (match_operand:SI 1 "offsettable_memory_operand" "o")
452490075Sobrien		   (const_int 16)))]
452590075Sobrien  "TARGET_ARM && (!TARGET_MMU_TRAPS)"
452690075Sobrien  "*
452790075Sobrien  {
452890075Sobrien    rtx ops[2];
452990075Sobrien
453090075Sobrien    ops[0] = operands[0];
453190075Sobrien    ops[1] = gen_rtx_MEM (SImode, plus_constant (XEXP (operands[1], 0), 2));
453290075Sobrien    output_asm_insn (\"ldr%?\\t%0, %1\\t%@ load-rotate\", ops);
453390075Sobrien    return \"\";
453490075Sobrien  }"
453590075Sobrien  [(set_attr "type" "load")
453690075Sobrien   (set_attr "predicable" "yes")]
453790075Sobrien)
453890075Sobrien
453990075Sobrien(define_expand "movhi_bytes"
454090075Sobrien  [(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" "")))
454190075Sobrien   (set (match_dup 3)
454290075Sobrien	(zero_extend:SI (match_dup 6)))
454390075Sobrien   (set (match_operand:SI 0 "" "")
454490075Sobrien	 (ior:SI (ashift:SI (match_dup 4) (const_int 8)) (match_dup 5)))]
454590075Sobrien  "TARGET_ARM"
454690075Sobrien  "
454790075Sobrien  {
454890075Sobrien    rtx mem1, mem2;
454990075Sobrien    rtx addr = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
455090075Sobrien
455190075Sobrien    mem1 = gen_rtx_MEM (QImode, addr);
455290075Sobrien    MEM_COPY_ATTRIBUTES (mem1, operands[1]);
455390075Sobrien    mem2 = gen_rtx_MEM (QImode, plus_constant (addr, 1));
455490075Sobrien    MEM_COPY_ATTRIBUTES (mem2, operands[1]);
455590075Sobrien    operands[0] = gen_lowpart (SImode, operands[0]);
455690075Sobrien    operands[1] = mem1;
455790075Sobrien    operands[2] = gen_reg_rtx (SImode);
455890075Sobrien    operands[3] = gen_reg_rtx (SImode);
455990075Sobrien    operands[6] = mem2;
456090075Sobrien
456190075Sobrien    if (BYTES_BIG_ENDIAN)
456290075Sobrien      {
456390075Sobrien	operands[4] = operands[2];
456490075Sobrien	operands[5] = operands[3];
456590075Sobrien      }
456690075Sobrien    else
456790075Sobrien      {
456890075Sobrien	operands[4] = operands[3];
456990075Sobrien	operands[5] = operands[2];
457090075Sobrien      }
457190075Sobrien  }"
457290075Sobrien)
457390075Sobrien
457490075Sobrien(define_expand "movhi_bigend"
457590075Sobrien  [(set (match_dup 2)
457690075Sobrien	(rotate:SI (subreg:SI (match_operand:HI 1 "memory_operand" "") 0)
457790075Sobrien		   (const_int 16)))
457890075Sobrien   (set (match_dup 3)
457990075Sobrien	(ashiftrt:SI (match_dup 2) (const_int 16)))
458090075Sobrien   (set (match_operand:HI 0 "s_register_operand" "")
4581132718Skan	(match_dup 4))]
458290075Sobrien  "TARGET_ARM"
458390075Sobrien  "
458490075Sobrien  operands[2] = gen_reg_rtx (SImode);
458590075Sobrien  operands[3] = gen_reg_rtx (SImode);
4586132718Skan  operands[4] = gen_lowpart (HImode, operands[3]);
458790075Sobrien  "
458890075Sobrien)
458990075Sobrien
4590117395Skan;; Pattern to recognize insn generated default case above
459190075Sobrien(define_insn "*movhi_insn_arch4"
459290075Sobrien  [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,m,r")    
459390075Sobrien	(match_operand:HI 1 "general_operand"      "rI,K,r,m"))]
459490075Sobrien  "TARGET_ARM
459590075Sobrien   && arm_arch4
459690075Sobrien   && (GET_CODE (operands[1]) != CONST_INT
459790075Sobrien       || const_ok_for_arm (INTVAL (operands[1]))
459890075Sobrien       || const_ok_for_arm (~INTVAL (operands[1])))"
459990075Sobrien  "@
460090075Sobrien   mov%?\\t%0, %1\\t%@ movhi
460190075Sobrien   mvn%?\\t%0, #%B1\\t%@ movhi
460290075Sobrien   str%?h\\t%1, %0\\t%@ movhi 
460390075Sobrien   ldr%?h\\t%0, %1\\t%@ movhi"
460490075Sobrien  [(set_attr "type" "*,*,store1,load")
460590075Sobrien   (set_attr "predicable" "yes")
460690075Sobrien   (set_attr "pool_range" "*,*,*,256")
460790075Sobrien   (set_attr "neg_pool_range" "*,*,*,244")]
460890075Sobrien)
460990075Sobrien
461090075Sobrien(define_insn "*movhi_insn_littleend"
461190075Sobrien  [(set (match_operand:HI 0 "s_register_operand" "=r,r,r")
461290075Sobrien	(match_operand:HI 1 "general_operand"  "rI,K,m"))]
461390075Sobrien  "TARGET_ARM
461490075Sobrien   && !arm_arch4
461590075Sobrien   && !BYTES_BIG_ENDIAN
461690075Sobrien   && !TARGET_MMU_TRAPS
461790075Sobrien   && (GET_CODE (operands[1]) != CONST_INT
461890075Sobrien       || const_ok_for_arm (INTVAL (operands[1]))
461990075Sobrien       || const_ok_for_arm (~INTVAL (operands[1])))"
462090075Sobrien  "@
462190075Sobrien   mov%?\\t%0, %1\\t%@ movhi
462290075Sobrien   mvn%?\\t%0, #%B1\\t%@ movhi
462390075Sobrien   ldr%?\\t%0, %1\\t%@ movhi"
462490075Sobrien  [(set_attr "type" "*,*,load")
462590075Sobrien   (set_attr "predicable" "yes")
462690075Sobrien   (set_attr "pool_range" "4096")
462790075Sobrien   (set_attr "neg_pool_range" "4084")]
462890075Sobrien)
462990075Sobrien
463090075Sobrien(define_insn "*movhi_insn_bigend"
463190075Sobrien  [(set (match_operand:HI 0 "s_register_operand" "=r,r,r")
463290075Sobrien	(match_operand:HI 1 "general_operand"    "rI,K,m"))]
463390075Sobrien  "TARGET_ARM
463490075Sobrien   && !arm_arch4
463590075Sobrien   && BYTES_BIG_ENDIAN
463690075Sobrien   && !TARGET_MMU_TRAPS
463790075Sobrien   && (GET_CODE (operands[1]) != CONST_INT
463890075Sobrien       || const_ok_for_arm (INTVAL (operands[1]))
463990075Sobrien       || const_ok_for_arm (~INTVAL (operands[1])))"
464090075Sobrien  "@
464190075Sobrien   mov%?\\t%0, %1\\t%@ movhi
464290075Sobrien   mvn%?\\t%0, #%B1\\t%@ movhi
464390075Sobrien   ldr%?\\t%0, %1\\t%@ movhi_bigend\;mov%?\\t%0, %0, asr #16"
464490075Sobrien  [(set_attr "type" "*,*,load")
464590075Sobrien   (set_attr "predicable" "yes")
464690075Sobrien   (set_attr "length" "4,4,8")
464790075Sobrien   (set_attr "pool_range" "*,*,4092")
464890075Sobrien   (set_attr "neg_pool_range" "*,*,4084")]
464990075Sobrien)
465090075Sobrien
465190075Sobrien(define_insn "*loadhi_si_bigend"
465290075Sobrien  [(set (match_operand:SI                       0 "s_register_operand" "=r")
465390075Sobrien	(rotate:SI (subreg:SI (match_operand:HI 1 "memory_operand"      "m") 0)
465490075Sobrien		   (const_int 16)))]
465590075Sobrien  "TARGET_ARM
465690075Sobrien   && BYTES_BIG_ENDIAN
465790075Sobrien   && !TARGET_MMU_TRAPS"
465890075Sobrien  "ldr%?\\t%0, %1\\t%@ movhi_bigend"
465990075Sobrien  [(set_attr "type" "load")
466090075Sobrien   (set_attr "predicable" "yes")
466190075Sobrien   (set_attr "pool_range" "4096")
466290075Sobrien   (set_attr "neg_pool_range" "4084")]
466390075Sobrien)
466490075Sobrien
466590075Sobrien(define_insn "*movhi_bytes"
466690075Sobrien  [(set (match_operand:HI 0 "s_register_operand" "=r,r")
466790075Sobrien	(match_operand:HI 1 "arm_rhs_operand"  "rI,K"))]
466890075Sobrien  "TARGET_ARM && TARGET_MMU_TRAPS"
466990075Sobrien  "@
467090075Sobrien   mov%?\\t%0, %1\\t%@ movhi
467190075Sobrien   mvn%?\\t%0, #%B1\\t%@ movhi"
467290075Sobrien  [(set_attr "predicable" "yes")]
467390075Sobrien)
467490075Sobrien
467590075Sobrien(define_insn "thumb_movhi_clobber"
467690075Sobrien  [(set (match_operand:HI     0 "memory_operand"   "=m")
467790075Sobrien	(match_operand:HI     1 "register_operand" "l"))
467890075Sobrien   (clobber (match_operand:SI 2 "register_operand" "=&l"))]
467990075Sobrien  "TARGET_THUMB"
468090075Sobrien  "*
468190075Sobrien  abort ();"
468290075Sobrien)
468390075Sobrien	
468490075Sobrien;; We use a DImode scratch because we may occasionally need an additional
468590075Sobrien;; temporary if the address isn't offsettable -- push_reload doesn't seem
468690075Sobrien;; to take any notice of the "o" constraints on reload_memory_operand operand.
468790075Sobrien(define_expand "reload_outhi"
468890075Sobrien  [(parallel [(match_operand:HI 0 "arm_reload_memory_operand" "=o")
468990075Sobrien	      (match_operand:HI 1 "s_register_operand"        "r")
469090075Sobrien	      (match_operand:DI 2 "s_register_operand"        "=&l")])]
469190075Sobrien  "TARGET_EITHER"
469290075Sobrien  "if (TARGET_ARM)
469390075Sobrien     arm_reload_out_hi (operands);
469490075Sobrien   else
469590075Sobrien     thumb_reload_out_hi (operands);
469690075Sobrien  DONE;
469790075Sobrien  "
469890075Sobrien)
469990075Sobrien
470090075Sobrien(define_expand "reload_inhi"
470190075Sobrien  [(parallel [(match_operand:HI 0 "s_register_operand" "=r")
470290075Sobrien	      (match_operand:HI 1 "arm_reload_memory_operand" "o")
470390075Sobrien	      (match_operand:DI 2 "s_register_operand" "=&r")])]
470490075Sobrien  "TARGET_THUMB || (TARGET_ARM && TARGET_MMU_TRAPS)"
470590075Sobrien  "
470690075Sobrien  if (TARGET_ARM)
470790075Sobrien    arm_reload_in_hi (operands);
470890075Sobrien  else
470990075Sobrien    thumb_reload_out_hi (operands);
471090075Sobrien  DONE;
471190075Sobrien")
471290075Sobrien
471390075Sobrien(define_expand "movqi"
471490075Sobrien  [(set (match_operand:QI 0 "general_operand" "")
471590075Sobrien        (match_operand:QI 1 "general_operand" ""))]
471690075Sobrien  "TARGET_EITHER"
471790075Sobrien  "
471890075Sobrien  if (TARGET_ARM)
471990075Sobrien    {
472090075Sobrien      /* Everything except mem = const or mem = mem can be done easily */
472190075Sobrien
472290075Sobrien      if (!no_new_pseudos)
472390075Sobrien        {
472490075Sobrien          if (GET_CODE (operands[1]) == CONST_INT)
472590075Sobrien	    {
472690075Sobrien	      rtx reg = gen_reg_rtx (SImode);
472790075Sobrien
472890075Sobrien	      emit_insn (gen_movsi (reg, operands[1]));
4729102780Skan	      operands[1] = gen_lowpart (QImode, reg);
473090075Sobrien	    }
4731117395Skan	  if (GET_CODE (operands[1]) == MEM && optimize > 0)
4732117395Skan	    {
4733117395Skan	      rtx reg = gen_reg_rtx (SImode);
4734117395Skan
4735117395Skan	      emit_insn (gen_zero_extendqisi2 (reg, operands[1]));
4736117395Skan	      operands[1] = gen_lowpart (QImode, reg);
4737117395Skan	    }
4738117395Skan          if (GET_CODE (operands[0]) == MEM)
4739117395Skan	    operands[1] = force_reg (QImode, operands[1]);
4740117395Skan        }
474190075Sobrien    }
474290075Sobrien  else /* TARGET_THUMB */
474390075Sobrien    {
474490075Sobrien      if (!no_new_pseudos)
474590075Sobrien        {
474690075Sobrien          if (GET_CODE (operands[0]) != REG)
474790075Sobrien	    operands[1] = force_reg (QImode, operands[1]);
474890075Sobrien
474990075Sobrien          /* ??? We shouldn't really get invalid addresses here, but this can
475090075Sobrien	     happen if we are passed a SP (never OK for HImode/QImode) or
475190075Sobrien	     virtual register (rejected by GO_IF_LEGITIMATE_ADDRESS for
475290075Sobrien	     HImode/QImode) relative address.  */
475390075Sobrien          /* ??? This should perhaps be fixed elsewhere, for instance, in
475490075Sobrien	     fixup_stack_1, by checking for other kinds of invalid addresses,
475590075Sobrien	     e.g. a bare reference to a virtual register.  This may confuse the
475690075Sobrien	     alpha though, which must handle this case differently.  */
475790075Sobrien          if (GET_CODE (operands[0]) == MEM
475890075Sobrien	      && !memory_address_p (GET_MODE (operands[0]),
475990075Sobrien		  		     XEXP (operands[0], 0)))
476090075Sobrien	    operands[0]
476190075Sobrien	      = replace_equiv_address (operands[0],
476290075Sobrien				       copy_to_reg (XEXP (operands[0], 0)));
476390075Sobrien          if (GET_CODE (operands[1]) == MEM
476490075Sobrien	      && !memory_address_p (GET_MODE (operands[1]),
476590075Sobrien				    XEXP (operands[1], 0)))
476690075Sobrien	     operands[1]
476790075Sobrien	       = replace_equiv_address (operands[1],
476890075Sobrien					copy_to_reg (XEXP (operands[1], 0)));
476990075Sobrien        }
4770132718Skan      /* Handle loading a large integer during reload.  */
477190075Sobrien      else if (GET_CODE (operands[1]) == CONST_INT
477290075Sobrien	       && !CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I'))
477390075Sobrien        {
477490075Sobrien          /* Writing a constant to memory needs a scratch, which should
477590075Sobrien	     be handled with SECONDARY_RELOADs.  */
477690075Sobrien          if (GET_CODE (operands[0]) != REG)
477790075Sobrien	    abort ();
477890075Sobrien
4779102780Skan          operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0);
478090075Sobrien          emit_insn (gen_movsi (operands[0], operands[1]));
478190075Sobrien          DONE;
478290075Sobrien       }
478390075Sobrien    }
478490075Sobrien  "
478590075Sobrien)
478690075Sobrien
478790075Sobrien
478890075Sobrien(define_insn "*arm_movqi_insn"
478990075Sobrien  [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r,m")
479090075Sobrien	(match_operand:QI 1 "general_operand" "rI,K,m,r"))]
479190075Sobrien  "TARGET_ARM
479290075Sobrien   && (   register_operand (operands[0], QImode)
479390075Sobrien       || register_operand (operands[1], QImode))"
479490075Sobrien  "@
479590075Sobrien   mov%?\\t%0, %1
479690075Sobrien   mvn%?\\t%0, #%B1
479790075Sobrien   ldr%?b\\t%0, %1
479890075Sobrien   str%?b\\t%1, %0"
479990075Sobrien  [(set_attr "type" "*,*,load,store1")
480090075Sobrien   (set_attr "predicable" "yes")]
480190075Sobrien)
480290075Sobrien
480390075Sobrien(define_insn "*thumb_movqi_insn"
480490075Sobrien  [(set (match_operand:QI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l")
480590075Sobrien	(match_operand:QI 1 "general_operand"      "l, m,l,*h,*r,I"))]
480690075Sobrien  "TARGET_THUMB
480790075Sobrien   && (   register_operand (operands[0], QImode)
480890075Sobrien       || register_operand (operands[1], QImode))"
480990075Sobrien  "@
481090075Sobrien   add\\t%0, %1, #0
481190075Sobrien   ldrb\\t%0, %1
481290075Sobrien   strb\\t%1, %0
481390075Sobrien   mov\\t%0, %1
481490075Sobrien   mov\\t%0, %1
481590075Sobrien   mov\\t%0, %1"
481690075Sobrien  [(set_attr "length" "2")
481790075Sobrien   (set_attr "type" "*,load,store1,*,*,*")
481890075Sobrien   (set_attr "pool_range" "*,32,*,*,*,*")]
481990075Sobrien)
482090075Sobrien
482190075Sobrien(define_expand "movsf"
482290075Sobrien  [(set (match_operand:SF 0 "general_operand" "")
482390075Sobrien	(match_operand:SF 1 "general_operand" ""))]
482490075Sobrien  "TARGET_EITHER"
482590075Sobrien  "
482690075Sobrien  if (TARGET_ARM)
482790075Sobrien    {
482890075Sobrien      if (GET_CODE (operands[0]) == MEM)
482990075Sobrien        operands[1] = force_reg (SFmode, operands[1]);
483090075Sobrien    }
483190075Sobrien  else /* TARGET_THUMB */
483290075Sobrien    {
483390075Sobrien      if (!no_new_pseudos)
483490075Sobrien        {
483590075Sobrien           if (GET_CODE (operands[0]) != REG)
483690075Sobrien	     operands[1] = force_reg (SFmode, operands[1]);
483790075Sobrien        }
483890075Sobrien    }
483990075Sobrien  "
484090075Sobrien)
484190075Sobrien
484290075Sobrien(define_split
484390075Sobrien  [(set (match_operand:SF 0 "nonimmediate_operand" "")
484490075Sobrien	(match_operand:SF 1 "immediate_operand" ""))]
484590075Sobrien  "TARGET_ARM
484690075Sobrien   && !TARGET_HARD_FLOAT
484790075Sobrien   && reload_completed
484890075Sobrien   && GET_CODE (operands[1]) == CONST_DOUBLE"
484990075Sobrien  [(set (match_dup 2) (match_dup 3))]
485090075Sobrien  "
485190075Sobrien  operands[2] = gen_lowpart (SImode, operands[0]);
485290075Sobrien  operands[3] = gen_lowpart (SImode, operands[1]);
485390075Sobrien  if (operands[2] == 0 || operands[3] == 0)
485490075Sobrien    FAIL;
485590075Sobrien  "
485690075Sobrien)
485790075Sobrien
485890075Sobrien(define_insn "*arm_movsf_soft_insn"
485990075Sobrien  [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m")
486090075Sobrien	(match_operand:SF 1 "general_operand"  "r,mE,r"))]
486190075Sobrien  "TARGET_ARM
4862132718Skan   && !TARGET_CIRRUS
486390075Sobrien   && TARGET_SOFT_FLOAT
486490075Sobrien   && (GET_CODE (operands[0]) != MEM
486590075Sobrien       || register_operand (operands[1], SFmode))"
486690075Sobrien  "@
486790075Sobrien   mov%?\\t%0, %1
486890075Sobrien   ldr%?\\t%0, %1\\t%@ float
486990075Sobrien   str%?\\t%1, %0\\t%@ float"
487090075Sobrien  [(set_attr "length" "4,4,4")
487190075Sobrien   (set_attr "predicable" "yes")
487290075Sobrien   (set_attr "type" "*,load,store1")
487390075Sobrien   (set_attr "pool_range" "*,4096,*")
487490075Sobrien   (set_attr "neg_pool_range" "*,4084,*")]
487590075Sobrien)
487690075Sobrien
487790075Sobrien;;; ??? This should have alternatives for constants.
487890075Sobrien(define_insn "*thumb_movsf_insn"
487990075Sobrien  [(set (match_operand:SF     0 "nonimmediate_operand" "=l,l,>,l, m,*r,*h")
488090075Sobrien	(match_operand:SF     1 "general_operand"      "l, >,l,mF,l,*h,*r"))]
488190075Sobrien  "TARGET_THUMB
488290075Sobrien   && (   register_operand (operands[0], SFmode) 
488390075Sobrien       || register_operand (operands[1], SFmode))"
488490075Sobrien  "@
488590075Sobrien   add\\t%0, %1, #0
488690075Sobrien   ldmia\\t%1, {%0}
488790075Sobrien   stmia\\t%0, {%1}
488890075Sobrien   ldr\\t%0, %1
488990075Sobrien   str\\t%1, %0
489090075Sobrien   mov\\t%0, %1
489190075Sobrien   mov\\t%0, %1"
489290075Sobrien  [(set_attr "length" "2")
489390075Sobrien   (set_attr "type" "*,load,store1,load,store1,*,*")
489490075Sobrien   (set_attr "pool_range" "*,*,*,1020,*,*,*")]
489590075Sobrien)
489690075Sobrien
489790075Sobrien(define_expand "movdf"
489890075Sobrien  [(set (match_operand:DF 0 "general_operand" "")
489990075Sobrien	(match_operand:DF 1 "general_operand" ""))]
490090075Sobrien  "TARGET_EITHER"
490190075Sobrien  "
490290075Sobrien  if (TARGET_ARM)
490390075Sobrien    {
490490075Sobrien      if (GET_CODE (operands[0]) == MEM)
490590075Sobrien        operands[1] = force_reg (DFmode, operands[1]);
490690075Sobrien    }
490790075Sobrien  else /* TARGET_THUMB */
490890075Sobrien    {
490990075Sobrien      if (!no_new_pseudos)
491090075Sobrien        {
491190075Sobrien          if (GET_CODE (operands[0]) != REG)
491290075Sobrien	    operands[1] = force_reg (DFmode, operands[1]);
491390075Sobrien        }
491490075Sobrien    }
491590075Sobrien  "
491690075Sobrien)
491790075Sobrien
491890075Sobrien;; Reloading a df mode value stored in integer regs to memory can require a
491990075Sobrien;; scratch reg.
492090075Sobrien(define_expand "reload_outdf"
492190075Sobrien  [(match_operand:DF 0 "arm_reload_memory_operand" "=o")
492290075Sobrien   (match_operand:DF 1 "s_register_operand" "r")
492390075Sobrien   (match_operand:SI 2 "s_register_operand" "=&r")]
492490075Sobrien  "TARGET_ARM"
492590075Sobrien  "
492690075Sobrien  {
492790075Sobrien    enum rtx_code code = GET_CODE (XEXP (operands[0], 0));
492890075Sobrien
492990075Sobrien    if (code == REG)
493090075Sobrien      operands[2] = XEXP (operands[0], 0);
493190075Sobrien    else if (code == POST_INC || code == PRE_DEC)
493290075Sobrien      {
493390075Sobrien	operands[0] = gen_rtx_SUBREG (DImode, operands[0], 0);
493490075Sobrien	operands[1] = gen_rtx_SUBREG (DImode, operands[1], 0);
493590075Sobrien	emit_insn (gen_movdi (operands[0], operands[1]));
493690075Sobrien	DONE;
493790075Sobrien      }
493890075Sobrien    else if (code == PRE_INC)
493990075Sobrien      {
494090075Sobrien	rtx reg = XEXP (XEXP (operands[0], 0), 0);
494190075Sobrien
494290075Sobrien	emit_insn (gen_addsi3 (reg, reg, GEN_INT (8)));
494390075Sobrien	operands[2] = reg;
494490075Sobrien      }
494590075Sobrien    else if (code == POST_DEC)
494690075Sobrien      operands[2] = XEXP (XEXP (operands[0], 0), 0);
494790075Sobrien    else
494890075Sobrien      emit_insn (gen_addsi3 (operands[2], XEXP (XEXP (operands[0], 0), 0),
494990075Sobrien			     XEXP (XEXP (operands[0], 0), 1)));
495090075Sobrien
495190075Sobrien    emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_MEM (DFmode, operands[2]),
495290075Sobrien			    operands[1]));
495390075Sobrien
495490075Sobrien    if (code == POST_DEC)
495590075Sobrien      emit_insn (gen_addsi3 (operands[2], operands[2], GEN_INT (-8)));
495690075Sobrien
495790075Sobrien    DONE;
495890075Sobrien  }"
495990075Sobrien)
496090075Sobrien
496190075Sobrien(define_insn "*movdf_soft_insn"
496290075Sobrien  [(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=r,r,m")
496390075Sobrien	(match_operand:DF 1 "soft_df_operand" "r,mF,r"))]
496490075Sobrien  "TARGET_ARM && TARGET_SOFT_FLOAT
4965132718Skan   && !TARGET_CIRRUS
496690075Sobrien  "
496790075Sobrien  "* return output_move_double (operands);"
496890075Sobrien  [(set_attr "length" "8,8,8")
496990075Sobrien   (set_attr "type" "*,load,store2")
497096263Sobrien   (set_attr "pool_range" "1020")
497196263Sobrien   (set_attr "neg_pool_range" "1008")]
497290075Sobrien)
497390075Sobrien
497490075Sobrien;;; ??? This should have alternatives for constants.
497590075Sobrien;;; ??? This was originally identical to the movdi_insn pattern.
497690075Sobrien;;; ??? The 'F' constraint looks funny, but it should always be replaced by
497790075Sobrien;;; thumb_reorg with a memory reference.
497890075Sobrien(define_insn "*thumb_movdf_insn"
497990075Sobrien  [(set (match_operand:DF 0 "nonimmediate_operand" "=l,l,>,l, m,*r")
498090075Sobrien	(match_operand:DF 1 "general_operand"      "l, >,l,mF,l,*r"))]
498190075Sobrien  "TARGET_THUMB
498290075Sobrien   && (   register_operand (operands[0], DFmode)
498390075Sobrien       || register_operand (operands[1], DFmode))"
498490075Sobrien  "*
498590075Sobrien  switch (which_alternative)
498690075Sobrien    {
498790075Sobrien    default:
498890075Sobrien    case 0:
498990075Sobrien      if (REGNO (operands[1]) == REGNO (operands[0]) + 1)
499090075Sobrien	return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\";
499190075Sobrien      return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\";
499290075Sobrien    case 1:
499390075Sobrien      return \"ldmia\\t%1, {%0, %H0}\";
499490075Sobrien    case 2:
499590075Sobrien      return \"stmia\\t%0, {%1, %H1}\";
499690075Sobrien    case 3:
499790075Sobrien      return thumb_load_double_from_address (operands);
499890075Sobrien    case 4:
499990075Sobrien      operands[2] = gen_rtx (MEM, SImode,
500090075Sobrien			     plus_constant (XEXP (operands[0], 0), 4));
500190075Sobrien      output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands);
500290075Sobrien      return \"\";
500390075Sobrien    case 5:
500490075Sobrien      if (REGNO (operands[1]) == REGNO (operands[0]) + 1)
500590075Sobrien	return \"mov\\t%0, %1\;mov\\t%H0, %H1\";
500690075Sobrien      return \"mov\\t%H0, %H1\;mov\\t%0, %1\";
500790075Sobrien    }
500890075Sobrien  "
500990075Sobrien  [(set_attr "length" "4,2,2,6,4,4")
501090075Sobrien   (set_attr "type" "*,load,store2,load,store2,*")
501190075Sobrien   (set_attr "pool_range" "*,*,*,1020,*,*")]
501290075Sobrien)
501390075Sobrien
5014132718Skan;; Vector Moves
5015132718Skan(define_expand "movv2si"
5016132718Skan  [(set (match_operand:V2SI 0 "nonimmediate_operand" "")
5017132718Skan	(match_operand:V2SI 1 "general_operand" ""))]
5018132718Skan  "TARGET_REALLY_IWMMXT"
5019132718Skan{
5020132718Skan})
502190075Sobrien
5022132718Skan(define_expand "movv4hi"
5023132718Skan  [(set (match_operand:V4HI 0 "nonimmediate_operand" "")
5024132718Skan	(match_operand:V4HI 1 "general_operand" ""))]
5025132718Skan  "TARGET_REALLY_IWMMXT"
5026132718Skan{
5027132718Skan})
502890075Sobrien
5029132718Skan(define_expand "movv8qi"
5030132718Skan  [(set (match_operand:V8QI 0 "nonimmediate_operand" "")
5031132718Skan	(match_operand:V8QI 1 "general_operand" ""))]
5032132718Skan  "TARGET_REALLY_IWMMXT"
5033132718Skan{
5034132718Skan})
503590075Sobrien
503690075Sobrien
503790075Sobrien;; load- and store-multiple insns
503890075Sobrien;; The arm can load/store any set of registers, provided that they are in
503990075Sobrien;; ascending order; but that is beyond GCC so stick with what it knows.
504090075Sobrien
504190075Sobrien(define_expand "load_multiple"
504290075Sobrien  [(match_par_dup 3 [(set (match_operand:SI 0 "" "")
504390075Sobrien                          (match_operand:SI 1 "" ""))
504490075Sobrien                     (use (match_operand:SI 2 "" ""))])]
504590075Sobrien  "TARGET_ARM"
504690075Sobrien  "
504790075Sobrien  /* Support only fixed point registers.  */
504890075Sobrien  if (GET_CODE (operands[2]) != CONST_INT
504990075Sobrien      || INTVAL (operands[2]) > 14
505090075Sobrien      || INTVAL (operands[2]) < 2
505190075Sobrien      || GET_CODE (operands[1]) != MEM
505290075Sobrien      || GET_CODE (operands[0]) != REG
505390075Sobrien      || REGNO (operands[0]) > (LAST_ARM_REGNUM - 1)
505490075Sobrien      || REGNO (operands[0]) + INTVAL (operands[2]) > LAST_ARM_REGNUM)
505590075Sobrien    FAIL;
505690075Sobrien
505790075Sobrien  operands[3]
505890075Sobrien    = arm_gen_load_multiple (REGNO (operands[0]), INTVAL (operands[2]),
505990075Sobrien			     force_reg (SImode, XEXP (operands[1], 0)),
506090075Sobrien			     TRUE, FALSE, RTX_UNCHANGING_P(operands[1]),
506190075Sobrien			     MEM_IN_STRUCT_P(operands[1]),
506290075Sobrien	                     MEM_SCALAR_P (operands[1]));
506390075Sobrien  "
506490075Sobrien)
506590075Sobrien
506690075Sobrien;; Load multiple with write-back
506790075Sobrien
506890075Sobrien(define_insn "*ldmsi_postinc4"
506990075Sobrien  [(match_parallel 0 "load_multiple_operation"
507090075Sobrien    [(set (match_operand:SI 1 "s_register_operand" "=r")
507190075Sobrien	  (plus:SI (match_operand:SI 2 "s_register_operand" "1")
507290075Sobrien		   (const_int 16)))
507390075Sobrien     (set (match_operand:SI 3 "arm_hard_register_operand" "")
507490075Sobrien	  (mem:SI (match_dup 2)))
507590075Sobrien     (set (match_operand:SI 4 "arm_hard_register_operand" "")
507690075Sobrien	  (mem:SI (plus:SI (match_dup 2) (const_int 4))))
507790075Sobrien     (set (match_operand:SI 5 "arm_hard_register_operand" "")
507890075Sobrien	  (mem:SI (plus:SI (match_dup 2) (const_int 8))))
507990075Sobrien     (set (match_operand:SI 6 "arm_hard_register_operand" "")
508090075Sobrien	  (mem:SI (plus:SI (match_dup 2) (const_int 12))))])]
508190075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 5"
508290075Sobrien  "ldm%?ia\\t%1!, {%3, %4, %5, %6}"
508390075Sobrien  [(set_attr "type" "load")
508490075Sobrien   (set_attr "predicable" "yes")]
508590075Sobrien)
508690075Sobrien
508790075Sobrien(define_insn "*ldmsi_postinc3"
508890075Sobrien  [(match_parallel 0 "load_multiple_operation"
508990075Sobrien    [(set (match_operand:SI 1 "s_register_operand" "=r")
509090075Sobrien	  (plus:SI (match_operand:SI 2 "s_register_operand" "1")
509190075Sobrien		   (const_int 12)))
509290075Sobrien     (set (match_operand:SI 3 "arm_hard_register_operand" "")
509390075Sobrien	  (mem:SI (match_dup 2)))
509490075Sobrien     (set (match_operand:SI 4 "arm_hard_register_operand" "")
509590075Sobrien	  (mem:SI (plus:SI (match_dup 2) (const_int 4))))
509690075Sobrien     (set (match_operand:SI 5 "arm_hard_register_operand" "")
509790075Sobrien	  (mem:SI (plus:SI (match_dup 2) (const_int 8))))])]
509890075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 4"
509990075Sobrien  "ldm%?ia\\t%1!, {%3, %4, %5}"
510090075Sobrien  [(set_attr "type" "load")
510190075Sobrien   (set_attr "predicable" "yes")]
510290075Sobrien)
510390075Sobrien
510490075Sobrien(define_insn "*ldmsi_postinc2"
510590075Sobrien  [(match_parallel 0 "load_multiple_operation"
510690075Sobrien    [(set (match_operand:SI 1 "s_register_operand" "=r")
510790075Sobrien	  (plus:SI (match_operand:SI 2 "s_register_operand" "1")
510890075Sobrien		   (const_int 8)))
510990075Sobrien     (set (match_operand:SI 3 "arm_hard_register_operand" "")
511090075Sobrien	  (mem:SI (match_dup 2)))
511190075Sobrien     (set (match_operand:SI 4 "arm_hard_register_operand" "")
511290075Sobrien	  (mem:SI (plus:SI (match_dup 2) (const_int 4))))])]
511390075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 3"
511490075Sobrien  "ldm%?ia\\t%1!, {%3, %4}"
511590075Sobrien  [(set_attr "type" "load")
511690075Sobrien   (set_attr "predicable" "yes")]
511790075Sobrien)
511890075Sobrien
511990075Sobrien;; Ordinary load multiple
512090075Sobrien
512190075Sobrien(define_insn "*ldmsi4"
512290075Sobrien  [(match_parallel 0 "load_multiple_operation"
512390075Sobrien    [(set (match_operand:SI 2 "arm_hard_register_operand" "")
512490075Sobrien	  (mem:SI (match_operand:SI 1 "s_register_operand" "r")))
512590075Sobrien     (set (match_operand:SI 3 "arm_hard_register_operand" "")
512690075Sobrien	  (mem:SI (plus:SI (match_dup 1) (const_int 4))))
512790075Sobrien     (set (match_operand:SI 4 "arm_hard_register_operand" "")
512890075Sobrien	  (mem:SI (plus:SI (match_dup 1) (const_int 8))))
512990075Sobrien     (set (match_operand:SI 5 "arm_hard_register_operand" "")
513090075Sobrien	  (mem:SI (plus:SI (match_dup 1) (const_int 12))))])]
513190075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 4"
513290075Sobrien  "ldm%?ia\\t%1, {%2, %3, %4, %5}"
513390075Sobrien  [(set_attr "type" "load")
513490075Sobrien   (set_attr "predicable" "yes")]
513590075Sobrien)
513690075Sobrien
513790075Sobrien(define_insn "*ldmsi3"
513890075Sobrien  [(match_parallel 0 "load_multiple_operation"
513990075Sobrien    [(set (match_operand:SI 2 "arm_hard_register_operand" "")
514090075Sobrien	  (mem:SI (match_operand:SI 1 "s_register_operand" "r")))
514190075Sobrien     (set (match_operand:SI 3 "arm_hard_register_operand" "")
514290075Sobrien	  (mem:SI (plus:SI (match_dup 1) (const_int 4))))
514390075Sobrien     (set (match_operand:SI 4 "arm_hard_register_operand" "")
514490075Sobrien	  (mem:SI (plus:SI (match_dup 1) (const_int 8))))])]
514590075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 3"
514690075Sobrien  "ldm%?ia\\t%1, {%2, %3, %4}"
514790075Sobrien  [(set_attr "type" "load")
514890075Sobrien   (set_attr "predicable" "yes")]
514990075Sobrien)
515090075Sobrien
515190075Sobrien(define_insn "*ldmsi2"
515290075Sobrien  [(match_parallel 0 "load_multiple_operation"
515390075Sobrien    [(set (match_operand:SI 2 "arm_hard_register_operand" "")
515490075Sobrien	  (mem:SI (match_operand:SI 1 "s_register_operand" "r")))
515590075Sobrien     (set (match_operand:SI 3 "arm_hard_register_operand" "")
515690075Sobrien	  (mem:SI (plus:SI (match_dup 1) (const_int 4))))])]
515790075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 2"
515890075Sobrien  "ldm%?ia\\t%1, {%2, %3}"
515990075Sobrien  [(set_attr "type" "load")
516090075Sobrien   (set_attr "predicable" "yes")]
516190075Sobrien)
516290075Sobrien
516390075Sobrien(define_expand "store_multiple"
516490075Sobrien  [(match_par_dup 3 [(set (match_operand:SI 0 "" "")
516590075Sobrien                          (match_operand:SI 1 "" ""))
516690075Sobrien                     (use (match_operand:SI 2 "" ""))])]
516790075Sobrien  "TARGET_ARM"
516890075Sobrien  "
5169132718Skan  /* Support only fixed point registers.  */
517090075Sobrien  if (GET_CODE (operands[2]) != CONST_INT
517190075Sobrien      || INTVAL (operands[2]) > 14
517290075Sobrien      || INTVAL (operands[2]) < 2
517390075Sobrien      || GET_CODE (operands[1]) != REG
517490075Sobrien      || GET_CODE (operands[0]) != MEM
517590075Sobrien      || REGNO (operands[1]) > (LAST_ARM_REGNUM - 1)
517690075Sobrien      || REGNO (operands[1]) + INTVAL (operands[2]) > LAST_ARM_REGNUM)
517790075Sobrien    FAIL;
517890075Sobrien
517990075Sobrien  operands[3]
518090075Sobrien    = arm_gen_store_multiple (REGNO (operands[1]), INTVAL (operands[2]),
518190075Sobrien			      force_reg (SImode, XEXP (operands[0], 0)),
518290075Sobrien			      TRUE, FALSE, RTX_UNCHANGING_P (operands[0]),
518390075Sobrien			      MEM_IN_STRUCT_P(operands[0]), 
518490075Sobrien	                      MEM_SCALAR_P (operands[0]));
518590075Sobrien  "
518690075Sobrien)
518790075Sobrien
518890075Sobrien;; Store multiple with write-back
518990075Sobrien
519090075Sobrien(define_insn "*stmsi_postinc4"
519190075Sobrien  [(match_parallel 0 "store_multiple_operation"
519290075Sobrien    [(set (match_operand:SI 1 "s_register_operand" "=r")
519390075Sobrien	  (plus:SI (match_operand:SI 2 "s_register_operand" "1")
519490075Sobrien		   (const_int 16)))
519590075Sobrien     (set (mem:SI (match_dup 2))
519690075Sobrien	  (match_operand:SI 3 "arm_hard_register_operand" ""))
519790075Sobrien     (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
519890075Sobrien	  (match_operand:SI 4 "arm_hard_register_operand" ""))
519990075Sobrien     (set (mem:SI (plus:SI (match_dup 2) (const_int 8)))
520090075Sobrien	  (match_operand:SI 5 "arm_hard_register_operand" ""))
520190075Sobrien     (set (mem:SI (plus:SI (match_dup 2) (const_int 12)))
520290075Sobrien	  (match_operand:SI 6 "arm_hard_register_operand" ""))])]
520390075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 5"
520490075Sobrien  "stm%?ia\\t%1!, {%3, %4, %5, %6}"
520590075Sobrien  [(set_attr "predicable" "yes")
520690075Sobrien   (set_attr "type" "store4")]
520790075Sobrien)
520890075Sobrien
520990075Sobrien(define_insn "*stmsi_postinc3"
521090075Sobrien  [(match_parallel 0 "store_multiple_operation"
521190075Sobrien    [(set (match_operand:SI 1 "s_register_operand" "=r")
521290075Sobrien	  (plus:SI (match_operand:SI 2 "s_register_operand" "1")
521390075Sobrien		   (const_int 12)))
521490075Sobrien     (set (mem:SI (match_dup 2))
521590075Sobrien	  (match_operand:SI 3 "arm_hard_register_operand" ""))
521690075Sobrien     (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
521790075Sobrien	  (match_operand:SI 4 "arm_hard_register_operand" ""))
521890075Sobrien     (set (mem:SI (plus:SI (match_dup 2) (const_int 8)))
521990075Sobrien	  (match_operand:SI 5 "arm_hard_register_operand" ""))])]
522090075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 4"
522190075Sobrien  "stm%?ia\\t%1!, {%3, %4, %5}"
522290075Sobrien  [(set_attr "predicable" "yes")
522390075Sobrien   (set_attr "type" "store3")]
522490075Sobrien)
522590075Sobrien
522690075Sobrien(define_insn "*stmsi_postinc2"
522790075Sobrien  [(match_parallel 0 "store_multiple_operation"
522890075Sobrien    [(set (match_operand:SI 1 "s_register_operand" "=r")
522990075Sobrien	  (plus:SI (match_operand:SI 2 "s_register_operand" "1")
523090075Sobrien		   (const_int 8)))
523190075Sobrien     (set (mem:SI (match_dup 2))
523290075Sobrien	  (match_operand:SI 3 "arm_hard_register_operand" ""))
523390075Sobrien     (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
523490075Sobrien	  (match_operand:SI 4 "arm_hard_register_operand" ""))])]
523590075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 3"
523690075Sobrien  "stm%?ia\\t%1!, {%3, %4}"
523790075Sobrien  [(set_attr "predicable" "yes")
523890075Sobrien   (set_attr "type" "store2")]
523990075Sobrien)
524090075Sobrien
524190075Sobrien;; Ordinary store multiple
524290075Sobrien
524390075Sobrien(define_insn "*stmsi4"
524490075Sobrien  [(match_parallel 0 "store_multiple_operation"
524590075Sobrien    [(set (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
524690075Sobrien	  (match_operand:SI 2 "arm_hard_register_operand" ""))
524790075Sobrien     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
524890075Sobrien	  (match_operand:SI 3 "arm_hard_register_operand" ""))
524990075Sobrien     (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
525090075Sobrien	  (match_operand:SI 4 "arm_hard_register_operand" ""))
525190075Sobrien     (set (mem:SI (plus:SI (match_dup 1) (const_int 12)))
525290075Sobrien	  (match_operand:SI 5 "arm_hard_register_operand" ""))])]
525390075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 4"
525490075Sobrien  "stm%?ia\\t%1, {%2, %3, %4, %5}"
525590075Sobrien  [(set_attr "predicable" "yes")
525690075Sobrien   (set_attr "type" "store4")]
525790075Sobrien)
525890075Sobrien
525990075Sobrien(define_insn "*stmsi3"
526090075Sobrien  [(match_parallel 0 "store_multiple_operation"
526190075Sobrien    [(set (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
526290075Sobrien	  (match_operand:SI 2 "arm_hard_register_operand" ""))
526390075Sobrien     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
526490075Sobrien	  (match_operand:SI 3 "arm_hard_register_operand" ""))
526590075Sobrien     (set (mem:SI (plus:SI (match_dup 1) (const_int 8)))
526690075Sobrien	  (match_operand:SI 4 "arm_hard_register_operand" ""))])]
526790075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 3"
526890075Sobrien  "stm%?ia\\t%1, {%2, %3, %4}"
526990075Sobrien  [(set_attr "predicable" "yes")
527090075Sobrien   (set_attr "type" "store3")]
527190075Sobrien)
527290075Sobrien
527390075Sobrien(define_insn "*stmsi2"
527490075Sobrien  [(match_parallel 0 "store_multiple_operation"
527590075Sobrien    [(set (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
527690075Sobrien	  (match_operand:SI 2 "arm_hard_register_operand" ""))
527790075Sobrien     (set (mem:SI (plus:SI (match_dup 1) (const_int 4)))
527890075Sobrien	  (match_operand:SI 3 "arm_hard_register_operand" ""))])]
527990075Sobrien  "TARGET_ARM && XVECLEN (operands[0], 0) == 2"
528090075Sobrien  "stm%?ia\\t%1, {%2, %3}"
528190075Sobrien  [(set_attr "predicable" "yes")
528290075Sobrien   (set_attr "type" "store2")]
528390075Sobrien)
528490075Sobrien
528590075Sobrien;; Move a block of memory if it is word aligned and MORE than 2 words long.
528690075Sobrien;; We could let this apply for blocks of less than this, but it clobbers so
528790075Sobrien;; many registers that there is then probably a better way.
528890075Sobrien
528990075Sobrien(define_expand "movstrqi"
529090075Sobrien  [(match_operand:BLK 0 "general_operand" "")
529190075Sobrien   (match_operand:BLK 1 "general_operand" "")
529290075Sobrien   (match_operand:SI 2 "const_int_operand" "")
529390075Sobrien   (match_operand:SI 3 "const_int_operand" "")]
529490075Sobrien  "TARGET_EITHER"
529590075Sobrien  "
529690075Sobrien  if (TARGET_ARM)
529790075Sobrien    {
529890075Sobrien      if (arm_gen_movstrqi (operands))
529990075Sobrien        DONE;
530090075Sobrien      FAIL;
530190075Sobrien    }
530290075Sobrien  else /* TARGET_THUMB */
530390075Sobrien    {
530490075Sobrien      if (   INTVAL (operands[3]) != 4
530590075Sobrien          || INTVAL (operands[2]) > 48)
530690075Sobrien        FAIL;
530790075Sobrien
530890075Sobrien      thumb_expand_movstrqi (operands);
530990075Sobrien      DONE;
531090075Sobrien    }
531190075Sobrien  "
531290075Sobrien)
531390075Sobrien
531490075Sobrien;; Thumb block-move insns
531590075Sobrien
531690075Sobrien(define_insn "movmem12b"
531790075Sobrien  [(set (mem:SI (match_operand:SI 2 "register_operand" "0"))
531890075Sobrien	(mem:SI (match_operand:SI 3 "register_operand" "1")))
531990075Sobrien   (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
532090075Sobrien	(mem:SI (plus:SI (match_dup 3) (const_int 4))))
532190075Sobrien   (set (mem:SI (plus:SI (match_dup 2) (const_int 8)))
532290075Sobrien	(mem:SI (plus:SI (match_dup 3) (const_int 8))))
532390075Sobrien   (set (match_operand:SI 0 "register_operand" "=l")
532490075Sobrien	(plus:SI (match_dup 2) (const_int 12)))
532590075Sobrien   (set (match_operand:SI 1 "register_operand" "=l")
532690075Sobrien	(plus:SI (match_dup 3) (const_int 12)))
532790075Sobrien   (clobber (match_scratch:SI 4 "=&l"))
532890075Sobrien   (clobber (match_scratch:SI 5 "=&l"))
532990075Sobrien   (clobber (match_scratch:SI 6 "=&l"))]
533090075Sobrien  "TARGET_THUMB"
533190075Sobrien  "* return thumb_output_move_mem_multiple (3, operands);"
533290075Sobrien  [(set_attr "length" "4")
533390075Sobrien   ; This isn't entirely accurate...  It loads as well, but in terms of
533490075Sobrien   ; scheduling the following insn it is better to consider it as a store
533590075Sobrien   (set_attr "type" "store3")]
533690075Sobrien)
533790075Sobrien
533890075Sobrien(define_insn "movmem8b"
533990075Sobrien  [(set (mem:SI (match_operand:SI 2 "register_operand" "0"))
534090075Sobrien	(mem:SI (match_operand:SI 3 "register_operand" "1")))
534190075Sobrien   (set (mem:SI (plus:SI (match_dup 2) (const_int 4)))
534290075Sobrien	(mem:SI (plus:SI (match_dup 3) (const_int 4))))
534390075Sobrien   (set (match_operand:SI 0 "register_operand" "=l")
534490075Sobrien	(plus:SI (match_dup 2) (const_int 8)))
534590075Sobrien   (set (match_operand:SI 1 "register_operand" "=l")
534690075Sobrien	(plus:SI (match_dup 3) (const_int 8)))
534790075Sobrien   (clobber (match_scratch:SI 4 "=&l"))
534890075Sobrien   (clobber (match_scratch:SI 5 "=&l"))]
534990075Sobrien  "TARGET_THUMB"
535090075Sobrien  "* return thumb_output_move_mem_multiple (2, operands);"
535190075Sobrien  [(set_attr "length" "4")
535290075Sobrien   ; This isn't entirely accurate...  It loads as well, but in terms of
535390075Sobrien   ; scheduling the following insn it is better to consider it as a store
535490075Sobrien   (set_attr "type" "store2")]
535590075Sobrien)
535690075Sobrien
535790075Sobrien
535890075Sobrien
535990075Sobrien;; Compare & branch insns
5360132718Skan;; The range calculations are based as follows:
536190075Sobrien;; For forward branches, the address calculation returns the address of
536290075Sobrien;; the next instruction.  This is 2 beyond the branch instruction.
536390075Sobrien;; For backward branches, the address calculation returns the address of
536490075Sobrien;; the first instruction in this pattern (cmp).  This is 2 before the branch
536590075Sobrien;; instruction for the shortest sequence, and 4 before the branch instruction
536690075Sobrien;; if we have to jump around an unconditional branch.
536790075Sobrien;; To the basic branch range the PC offset must be added (this is +4).
536890075Sobrien;; So for forward branches we have 
536990075Sobrien;;   (pos_range - pos_base_offs + pc_offs) = (pos_range - 2 + 4).
537090075Sobrien;; And for backward branches we have 
537190075Sobrien;;   (neg_range - neg_base_offs + pc_offs) = (neg_range - (-2 or -4) + 4).
537290075Sobrien;;
537390075Sobrien;; For a 'b'       pos_range = 2046, neg_range = -2048 giving (-2040->2048).
537490075Sobrien;; For a 'b<cond>' pos_range = 254,  neg_range = -256  giving (-250 ->256).
537590075Sobrien
5376132718Skan(define_expand "cbranchsi4"
5377132718Skan  [(set (pc) (if_then_else
5378132718Skan	      (match_operator 0 "arm_comparison_operator"
5379132718Skan	       [(match_operand:SI 1 "s_register_operand" "")
5380132718Skan	        (match_operand:SI 2 "nonmemory_operand" "")])
5381132718Skan	      (label_ref (match_operand 3 "" ""))
5382132718Skan	      (pc)))]
538390075Sobrien  "TARGET_THUMB"
5384132718Skan  "
5385132718Skan  if (thumb_cmpneg_operand (operands[2], SImode))
5386132718Skan    {
5387132718Skan      emit_jump_insn (gen_cbranchsi4_scratch (NULL, operands[1], operands[2],
5388132718Skan					      operands[3], operands[0]));
5389132718Skan      DONE;
5390132718Skan    }
5391132718Skan  if (!thumb_cmp_operand (operands[2], SImode))
5392132718Skan    operands[2] = force_reg (SImode, operands[2]);
5393132718Skan  ")
5394132718Skan
5395132718Skan(define_insn "*cbranchsi4_insn"
5396132718Skan  [(set (pc) (if_then_else
5397132718Skan	      (match_operator 0 "arm_comparison_operator"
5398132718Skan	       [(match_operand:SI 1 "s_register_operand" "l,*h")
5399132718Skan	        (match_operand:SI 2 "thumb_cmp_operand" "lI*h,*r")])
5400132718Skan	      (label_ref (match_operand 3 "" ""))
5401132718Skan	      (pc)))]
5402132718Skan  "TARGET_THUMB"
540390075Sobrien  "*
540490075Sobrien  output_asm_insn (\"cmp\\t%1, %2\", operands);
5405132718Skan
540690075Sobrien  switch (get_attr_length (insn))
540790075Sobrien    {
540890075Sobrien    case 4:  return \"b%d0\\t%l3\";
540990075Sobrien    case 6:  return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
541090075Sobrien    default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
541190075Sobrien    }
541290075Sobrien  "
541390075Sobrien  [(set (attr "far_jump")
541490075Sobrien        (if_then_else
541590075Sobrien	    (eq_attr "length" "8")
541690075Sobrien	    (const_string "yes")
541790075Sobrien            (const_string "no")))
541890075Sobrien   (set (attr "length") 
541990075Sobrien        (if_then_else
542090075Sobrien	    (and (ge (minus (match_dup 3) (pc)) (const_int -250))
542190075Sobrien	         (le (minus (match_dup 3) (pc)) (const_int 256)))
542290075Sobrien	    (const_int 4)
542390075Sobrien	    (if_then_else
542490075Sobrien	        (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
542590075Sobrien		     (le (minus (match_dup 3) (pc)) (const_int 2048)))
542690075Sobrien		(const_int 6)
542790075Sobrien		(const_int 8))))]
542890075Sobrien)
542990075Sobrien
5430132718Skan(define_insn "cbranchsi4_scratch"
5431132718Skan  [(set (pc) (if_then_else
5432132718Skan	      (match_operator 4 "arm_comparison_operator"
5433132718Skan	       [(match_operand:SI 1 "s_register_operand" "l,0")
5434132718Skan	        (match_operand:SI 2 "thumb_cmpneg_operand" "L,J")])
5435132718Skan	      (label_ref (match_operand 3 "" ""))
5436132718Skan	      (pc)))
5437132718Skan   (clobber (match_scratch:SI 0 "=l,l"))]
5438132718Skan  "TARGET_THUMB"
5439132718Skan  "*
5440132718Skan  output_asm_insn (\"add\\t%0, %1, #%n2\", operands);
5441132718Skan
5442132718Skan  switch (get_attr_length (insn))
5443132718Skan    {
5444132718Skan    case 4:  return \"b%d4\\t%l3\";
5445132718Skan    case 6:  return \"b%D4\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
5446132718Skan    default: return \"b%D4\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
5447132718Skan    }
5448132718Skan  "
5449132718Skan  [(set (attr "far_jump")
5450132718Skan        (if_then_else
5451132718Skan	    (eq_attr "length" "8")
5452132718Skan	    (const_string "yes")
5453132718Skan            (const_string "no")))
5454132718Skan   (set (attr "length") 
5455132718Skan        (if_then_else
5456132718Skan	    (and (ge (minus (match_dup 3) (pc)) (const_int -250))
5457132718Skan	         (le (minus (match_dup 3) (pc)) (const_int 256)))
5458132718Skan	    (const_int 4)
5459132718Skan	    (if_then_else
5460132718Skan	        (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
5461132718Skan		     (le (minus (match_dup 3) (pc)) (const_int 2048)))
5462132718Skan		(const_int 6)
5463132718Skan		(const_int 8))))]
5464132718Skan)
5465132718Skan(define_insn "*movsi_cbranchsi4"
5466132718Skan  [(set (pc)
5467132718Skan	(if_then_else
5468132718Skan	 (match_operator 3 "arm_comparison_operator"
5469132718Skan	  [(match_operand:SI 1 "s_register_operand" "0,l,l,l")
5470132718Skan	   (const_int 0)])
5471132718Skan	 (label_ref (match_operand 2 "" ""))
5472132718Skan	 (pc)))
5473132718Skan   (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,l,*h,*m")
5474132718Skan	(match_dup 1))]
5475132718Skan  "TARGET_THUMB"
5476132718Skan  "*{
5477132718Skan  if (which_alternative == 0)
5478132718Skan    output_asm_insn (\"cmp\t%0, #0\", operands);
5479132718Skan  else if (which_alternative == 1)
5480132718Skan    output_asm_insn (\"sub\t%0, %1, #0\", operands);
5481132718Skan  else
5482132718Skan    {
5483132718Skan      output_asm_insn (\"cmp\t%1, #0\", operands);
5484132718Skan      if (which_alternative == 2)
5485132718Skan	output_asm_insn (\"mov\t%0, %1\", operands);
5486132718Skan      else
5487132718Skan	output_asm_insn (\"str\t%1, %0\", operands);
5488132718Skan    }
5489132718Skan  switch (get_attr_length (insn) - ((which_alternative > 1) ? 2 : 0))
5490132718Skan    {
5491132718Skan    case 4:  return \"b%d3\\t%l2\";
5492132718Skan    case 6:  return \"b%D3\\t.LCB%=\;b\\t%l2\\t%@long jump\\n.LCB%=:\";
5493132718Skan    default: return \"b%D3\\t.LCB%=\;bl\\t%l2\\t%@far jump\\n.LCB%=:\";
5494132718Skan    }
5495132718Skan  }"
5496132718Skan  [(set (attr "far_jump")
5497132718Skan        (if_then_else
5498132718Skan	    (ior (and (gt (symbol_ref ("which_alternative"))
5499132718Skan	                  (const_int 1))
5500132718Skan		      (eq_attr "length" "8"))
5501132718Skan		 (eq_attr "length" "10"))
5502132718Skan	    (const_string "yes")
5503132718Skan            (const_string "no")))
5504132718Skan   (set (attr "length")
5505132718Skan     (if_then_else
5506132718Skan       (le (symbol_ref ("which_alternative"))
5507132718Skan		       (const_int 1))
5508132718Skan       (if_then_else
5509132718Skan	 (and (ge (minus (match_dup 2) (pc)) (const_int -250))
5510132718Skan	      (le (minus (match_dup 2) (pc)) (const_int 256)))
5511132718Skan	 (const_int 4)
5512132718Skan	 (if_then_else
5513132718Skan	   (and (ge (minus (match_dup 2) (pc)) (const_int -2040))
5514132718Skan		(le (minus (match_dup 2) (pc)) (const_int 2048)))
5515132718Skan	   (const_int 6)
5516132718Skan	   (const_int 8)))
5517132718Skan       (if_then_else
5518132718Skan	 (and (ge (minus (match_dup 2) (pc)) (const_int -248))
5519132718Skan	      (le (minus (match_dup 2) (pc)) (const_int 256)))
5520132718Skan	 (const_int 6)
5521132718Skan	 (if_then_else
5522132718Skan	   (and (ge (minus (match_dup 2) (pc)) (const_int -2038))
5523132718Skan		(le (minus (match_dup 2) (pc)) (const_int 2048)))
5524132718Skan	   (const_int 8)
5525132718Skan	   (const_int 10)))))]
5526132718Skan)
5527132718Skan
552890075Sobrien(define_insn "*negated_cbranchsi4"
552990075Sobrien  [(set (pc)
553090075Sobrien	(if_then_else
5531132718Skan	 (match_operator 0 "arm_comparison_operator"
5532132718Skan	  [(match_operand:SI 1 "s_register_operand" "l")
5533132718Skan	   (neg:SI (match_operand:SI 2 "s_register_operand" "l"))])
5534132718Skan	 (label_ref (match_operand 3 "" ""))
553590075Sobrien	 (pc)))]
553690075Sobrien  "TARGET_THUMB"
553790075Sobrien  "*
553890075Sobrien  output_asm_insn (\"cmn\\t%1, %2\", operands);
553990075Sobrien  switch (get_attr_length (insn))
554090075Sobrien    {
554190075Sobrien    case 4:  return \"b%d0\\t%l3\";
554290075Sobrien    case 6:  return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
554390075Sobrien    default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
554490075Sobrien    }
554590075Sobrien  "
554690075Sobrien  [(set (attr "far_jump")
554790075Sobrien        (if_then_else
554890075Sobrien	    (eq_attr "length" "8")
554990075Sobrien	    (const_string "yes")
555090075Sobrien            (const_string "no")))
555190075Sobrien   (set (attr "length") 
555290075Sobrien        (if_then_else
555390075Sobrien	    (and (ge (minus (match_dup 3) (pc)) (const_int -250))
555490075Sobrien	         (le (minus (match_dup 3) (pc)) (const_int 256)))
555590075Sobrien	    (const_int 4)
555690075Sobrien	    (if_then_else
555790075Sobrien	        (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
555890075Sobrien		     (le (minus (match_dup 3) (pc)) (const_int 2048)))
555990075Sobrien		(const_int 6)
556090075Sobrien		(const_int 8))))]
556190075Sobrien)
556290075Sobrien
5563132718Skan(define_insn "*tbit_cbranch"
5564132718Skan  [(set (pc)
5565132718Skan	(if_then_else
5566132718Skan	 (match_operator 0 "equality_operator"
5567132718Skan	  [(zero_extract:SI (match_operand:SI 1 "s_register_operand" "l")
5568132718Skan			    (const_int 1)
5569132718Skan			    (match_operand:SI 2 "const_int_operand" "i"))
5570132718Skan	   (const_int 0)])
5571132718Skan	 (label_ref (match_operand 3 "" ""))
5572132718Skan	 (pc)))
5573132718Skan   (clobber (match_scratch:SI 4 "=l"))]
5574132718Skan  "TARGET_THUMB"
5575132718Skan  "*
5576132718Skan  {
5577132718Skan  rtx op[3];
5578132718Skan  op[0] = operands[4];
5579132718Skan  op[1] = operands[1];
5580132718Skan  op[2] = GEN_INT (32 - 1 - INTVAL (operands[2]));
558190075Sobrien
5582132718Skan  output_asm_insn (\"lsl\\t%0, %1, %2\", op);
5583132718Skan  switch (get_attr_length (insn))
5584132718Skan    {
5585132718Skan    case 4:  return \"b%d0\\t%l3\";
5586132718Skan    case 6:  return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
5587132718Skan    default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
5588132718Skan    }
5589132718Skan  }"
5590132718Skan  [(set (attr "far_jump")
5591132718Skan        (if_then_else
5592132718Skan	    (eq_attr "length" "8")
5593132718Skan	    (const_string "yes")
5594132718Skan            (const_string "no")))
5595132718Skan   (set (attr "length") 
5596132718Skan        (if_then_else
5597132718Skan	    (and (ge (minus (match_dup 3) (pc)) (const_int -250))
5598132718Skan	         (le (minus (match_dup 3) (pc)) (const_int 256)))
5599132718Skan	    (const_int 4)
5600132718Skan	    (if_then_else
5601132718Skan	        (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
5602132718Skan		     (le (minus (match_dup 3) (pc)) (const_int 2048)))
5603132718Skan		(const_int 6)
5604132718Skan		(const_int 8))))]
5605132718Skan)
5606132718Skan  
5607132718Skan(define_insn "*tstsi3_cbranch"
5608132718Skan  [(set (pc)
5609132718Skan	(if_then_else
5610132718Skan	 (match_operator 3 "equality_operator"
5611132718Skan	  [(and:SI (match_operand:SI 0 "s_register_operand" "%l")
5612132718Skan		   (match_operand:SI 1 "s_register_operand" "l"))
5613132718Skan	   (const_int 0)])
5614132718Skan	 (label_ref (match_operand 2 "" ""))
5615132718Skan	 (pc)))]
5616132718Skan  "TARGET_THUMB"
5617132718Skan  "*
5618132718Skan  {
5619132718Skan  output_asm_insn (\"tst\\t%0, %1\", operands);
5620132718Skan  switch (get_attr_length (insn))
5621132718Skan    {
5622132718Skan    case 4:  return \"b%d3\\t%l2\";
5623132718Skan    case 6:  return \"b%D3\\t.LCB%=\;b\\t%l2\\t%@long jump\\n.LCB%=:\";
5624132718Skan    default: return \"b%D3\\t.LCB%=\;bl\\t%l2\\t%@far jump\\n.LCB%=:\";
5625132718Skan    }
5626132718Skan  }"
5627132718Skan  [(set (attr "far_jump")
5628132718Skan        (if_then_else
5629132718Skan	    (eq_attr "length" "8")
5630132718Skan	    (const_string "yes")
5631132718Skan            (const_string "no")))
5632132718Skan   (set (attr "length") 
5633132718Skan        (if_then_else
5634132718Skan	    (and (ge (minus (match_dup 2) (pc)) (const_int -250))
5635132718Skan	         (le (minus (match_dup 2) (pc)) (const_int 256)))
5636132718Skan	    (const_int 4)
5637132718Skan	    (if_then_else
5638132718Skan	        (and (ge (minus (match_dup 2) (pc)) (const_int -2040))
5639132718Skan		     (le (minus (match_dup 2) (pc)) (const_int 2048)))
5640132718Skan		(const_int 6)
5641132718Skan		(const_int 8))))]
5642132718Skan)
5643132718Skan  
5644132718Skan(define_insn "*andsi3_cbranch"
5645132718Skan  [(set (pc)
5646132718Skan	(if_then_else
5647132718Skan	 (match_operator 5 "equality_operator"
5648132718Skan	  [(and:SI (match_operand:SI 2 "s_register_operand" "%0,1,1,1")
5649132718Skan		   (match_operand:SI 3 "s_register_operand" "l,l,l,l"))
5650132718Skan	   (const_int 0)])
5651132718Skan	 (label_ref (match_operand 4 "" ""))
5652132718Skan	 (pc)))
5653132718Skan   (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,*?h,*?m,*?m")
5654132718Skan	(and:SI (match_dup 2) (match_dup 3)))
5655132718Skan   (clobber (match_scratch:SI 1 "=X,l,&l,&l"))]
5656132718Skan  "TARGET_THUMB"
5657132718Skan  "*
5658132718Skan  {
5659132718Skan  if (which_alternative == 0)
5660132718Skan    output_asm_insn (\"and\\t%0, %3\", operands);
5661132718Skan  else if (which_alternative == 1)
5662132718Skan    {
5663132718Skan      output_asm_insn (\"and\\t%1, %3\", operands);
5664132718Skan      output_asm_insn (\"mov\\t%0, %1\", operands);
5665132718Skan    }
5666132718Skan  else
5667132718Skan    {
5668132718Skan      output_asm_insn (\"and\\t%1, %3\", operands);
5669132718Skan      output_asm_insn (\"str\\t%1, %0\", operands);
5670132718Skan    }
5671132718Skan
5672132718Skan  switch (get_attr_length (insn) - (which_alternative ? 2 : 0))
5673132718Skan    {
5674132718Skan    case 4:  return \"b%d5\\t%l4\";
5675132718Skan    case 6:  return \"b%D5\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\";
5676132718Skan    default: return \"b%D5\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\";
5677132718Skan    }
5678132718Skan  }"
5679132718Skan  [(set (attr "far_jump")
5680132718Skan        (if_then_else
5681132718Skan	    (ior (and (eq (symbol_ref ("which_alternative"))
5682132718Skan	                  (const_int 0))
5683132718Skan		      (eq_attr "length" "8"))
5684132718Skan		 (eq_attr "length" "10"))
5685132718Skan	    (const_string "yes")
5686132718Skan            (const_string "no")))
5687132718Skan   (set (attr "length")
5688132718Skan     (if_then_else
5689132718Skan       (eq (symbol_ref ("which_alternative"))
5690132718Skan		       (const_int 0))
5691132718Skan       (if_then_else
5692132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -250))
5693132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
5694132718Skan	 (const_int 4)
5695132718Skan	 (if_then_else
5696132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2040))
5697132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
5698132718Skan	   (const_int 6)
5699132718Skan	   (const_int 8)))
5700132718Skan       (if_then_else
5701132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -248))
5702132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
5703132718Skan	 (const_int 6)
5704132718Skan	 (if_then_else
5705132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
5706132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
5707132718Skan	   (const_int 8)
5708132718Skan	   (const_int 10)))))]
5709132718Skan)
5710132718Skan
5711132718Skan(define_insn "*orrsi3_cbranch_scratch"
5712132718Skan  [(set (pc)
5713132718Skan	(if_then_else
5714132718Skan	 (match_operator 4 "equality_operator"
5715132718Skan	  [(ior:SI (match_operand:SI 1 "s_register_operand" "%0")
5716132718Skan		   (match_operand:SI 2 "s_register_operand" "l"))
5717132718Skan	   (const_int 0)])
5718132718Skan	 (label_ref (match_operand 3 "" ""))
5719132718Skan	 (pc)))
5720132718Skan   (clobber (match_scratch:SI 0 "=l"))]
5721132718Skan  "TARGET_THUMB"
5722132718Skan  "*
5723132718Skan  {
5724132718Skan  output_asm_insn (\"orr\\t%0, %2\", operands);
5725132718Skan  switch (get_attr_length (insn))
5726132718Skan    {
5727132718Skan    case 4:  return \"b%d4\\t%l3\";
5728132718Skan    case 6:  return \"b%D4\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
5729132718Skan    default: return \"b%D4\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
5730132718Skan    }
5731132718Skan  }"
5732132718Skan  [(set (attr "far_jump")
5733132718Skan        (if_then_else
5734132718Skan	    (eq_attr "length" "8")
5735132718Skan	    (const_string "yes")
5736132718Skan            (const_string "no")))
5737132718Skan   (set (attr "length") 
5738132718Skan        (if_then_else
5739132718Skan	    (and (ge (minus (match_dup 3) (pc)) (const_int -250))
5740132718Skan	         (le (minus (match_dup 3) (pc)) (const_int 256)))
5741132718Skan	    (const_int 4)
5742132718Skan	    (if_then_else
5743132718Skan	        (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
5744132718Skan		     (le (minus (match_dup 3) (pc)) (const_int 2048)))
5745132718Skan		(const_int 6)
5746132718Skan		(const_int 8))))]
5747132718Skan)
5748132718Skan  
5749132718Skan(define_insn "*orrsi3_cbranch"
5750132718Skan  [(set (pc)
5751132718Skan	(if_then_else
5752132718Skan	 (match_operator 5 "equality_operator"
5753132718Skan	  [(ior:SI (match_operand:SI 2 "s_register_operand" "%0,1,1,1")
5754132718Skan		   (match_operand:SI 3 "s_register_operand" "l,l,l,l"))
5755132718Skan	   (const_int 0)])
5756132718Skan	 (label_ref (match_operand 4 "" ""))
5757132718Skan	 (pc)))
5758132718Skan   (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,*?h,*?m,*?m")
5759132718Skan	(ior:SI (match_dup 2) (match_dup 3)))
5760132718Skan   (clobber (match_scratch:SI 1 "=X,l,&l,&l"))]
5761132718Skan  "TARGET_THUMB"
5762132718Skan  "*
5763132718Skan  {
5764132718Skan  if (which_alternative == 0)
5765132718Skan    output_asm_insn (\"orr\\t%0, %3\", operands);
5766132718Skan  else if (which_alternative == 1)
5767132718Skan    {
5768132718Skan      output_asm_insn (\"orr\\t%1, %3\", operands);
5769132718Skan      output_asm_insn (\"mov\\t%0, %1\", operands);
5770132718Skan    }
5771132718Skan  else
5772132718Skan    {
5773132718Skan      output_asm_insn (\"orr\\t%1, %3\", operands);
5774132718Skan      output_asm_insn (\"str\\t%1, %0\", operands);
5775132718Skan    }
5776132718Skan
5777132718Skan  switch (get_attr_length (insn) - (which_alternative ? 2 : 0))
5778132718Skan    {
5779132718Skan    case 4:  return \"b%d5\\t%l4\";
5780132718Skan    case 6:  return \"b%D5\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\";
5781132718Skan    default: return \"b%D5\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\";
5782132718Skan    }
5783132718Skan  }"
5784132718Skan  [(set (attr "far_jump")
5785132718Skan        (if_then_else
5786132718Skan	    (ior (and (eq (symbol_ref ("which_alternative"))
5787132718Skan	                  (const_int 0))
5788132718Skan		      (eq_attr "length" "8"))
5789132718Skan		 (eq_attr "length" "10"))
5790132718Skan	    (const_string "yes")
5791132718Skan            (const_string "no")))
5792132718Skan   (set (attr "length")
5793132718Skan     (if_then_else
5794132718Skan       (eq (symbol_ref ("which_alternative"))
5795132718Skan		       (const_int 0))
5796132718Skan       (if_then_else
5797132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -250))
5798132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
5799132718Skan	 (const_int 4)
5800132718Skan	 (if_then_else
5801132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2040))
5802132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
5803132718Skan	   (const_int 6)
5804132718Skan	   (const_int 8)))
5805132718Skan       (if_then_else
5806132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -248))
5807132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
5808132718Skan	 (const_int 6)
5809132718Skan	 (if_then_else
5810132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
5811132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
5812132718Skan	   (const_int 8)
5813132718Skan	   (const_int 10)))))]
5814132718Skan)
5815132718Skan
5816132718Skan(define_insn "*xorsi3_cbranch_scratch"
5817132718Skan  [(set (pc)
5818132718Skan	(if_then_else
5819132718Skan	 (match_operator 4 "equality_operator"
5820132718Skan	  [(xor:SI (match_operand:SI 1 "s_register_operand" "%0")
5821132718Skan		   (match_operand:SI 2 "s_register_operand" "l"))
5822132718Skan	   (const_int 0)])
5823132718Skan	 (label_ref (match_operand 3 "" ""))
5824132718Skan	 (pc)))
5825132718Skan   (clobber (match_scratch:SI 0 "=l"))]
5826132718Skan  "TARGET_THUMB"
5827132718Skan  "*
5828132718Skan  {
5829132718Skan  output_asm_insn (\"eor\\t%0, %2\", operands);
5830132718Skan  switch (get_attr_length (insn))
5831132718Skan    {
5832132718Skan    case 4:  return \"b%d4\\t%l3\";
5833132718Skan    case 6:  return \"b%D4\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
5834132718Skan    default: return \"b%D4\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
5835132718Skan    }
5836132718Skan  }"
5837132718Skan  [(set (attr "far_jump")
5838132718Skan        (if_then_else
5839132718Skan	    (eq_attr "length" "8")
5840132718Skan	    (const_string "yes")
5841132718Skan            (const_string "no")))
5842132718Skan   (set (attr "length") 
5843132718Skan        (if_then_else
5844132718Skan	    (and (ge (minus (match_dup 3) (pc)) (const_int -250))
5845132718Skan	         (le (minus (match_dup 3) (pc)) (const_int 256)))
5846132718Skan	    (const_int 4)
5847132718Skan	    (if_then_else
5848132718Skan	        (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
5849132718Skan		     (le (minus (match_dup 3) (pc)) (const_int 2048)))
5850132718Skan		(const_int 6)
5851132718Skan		(const_int 8))))]
5852132718Skan)
5853132718Skan  
5854132718Skan(define_insn "*xorsi3_cbranch"
5855132718Skan  [(set (pc)
5856132718Skan	(if_then_else
5857132718Skan	 (match_operator 5 "equality_operator"
5858132718Skan	  [(xor:SI (match_operand:SI 2 "s_register_operand" "%0,1,1,1")
5859132718Skan		   (match_operand:SI 3 "s_register_operand" "l,l,l,l"))
5860132718Skan	   (const_int 0)])
5861132718Skan	 (label_ref (match_operand 4 "" ""))
5862132718Skan	 (pc)))
5863132718Skan   (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,*?h,*?m,*?m")
5864132718Skan	(xor:SI (match_dup 2) (match_dup 3)))
5865132718Skan   (clobber (match_scratch:SI 1 "=X,l,&l,&l"))]
5866132718Skan  "TARGET_THUMB"
5867132718Skan  "*
5868132718Skan  {
5869132718Skan  if (which_alternative == 0)
5870132718Skan    output_asm_insn (\"eor\\t%0, %3\", operands);
5871132718Skan  else if (which_alternative == 1)
5872132718Skan    {
5873132718Skan      output_asm_insn (\"eor\\t%1, %3\", operands);
5874132718Skan      output_asm_insn (\"mov\\t%0, %1\", operands);
5875132718Skan    }
5876132718Skan  else
5877132718Skan    {
5878132718Skan      output_asm_insn (\"eor\\t%1, %3\", operands);
5879132718Skan      output_asm_insn (\"str\\t%1, %0\", operands);
5880132718Skan    }
5881132718Skan
5882132718Skan  switch (get_attr_length (insn) - (which_alternative ? 2 : 0))
5883132718Skan    {
5884132718Skan    case 4:  return \"b%d5\\t%l4\";
5885132718Skan    case 6:  return \"b%D5\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\";
5886132718Skan    default: return \"b%D5\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\";
5887132718Skan    }
5888132718Skan  }"
5889132718Skan  [(set (attr "far_jump")
5890132718Skan        (if_then_else
5891132718Skan	    (ior (and (eq (symbol_ref ("which_alternative"))
5892132718Skan	                  (const_int 0))
5893132718Skan		      (eq_attr "length" "8"))
5894132718Skan		 (eq_attr "length" "10"))
5895132718Skan	    (const_string "yes")
5896132718Skan            (const_string "no")))
5897132718Skan   (set (attr "length")
5898132718Skan     (if_then_else
5899132718Skan       (eq (symbol_ref ("which_alternative"))
5900132718Skan		       (const_int 0))
5901132718Skan       (if_then_else
5902132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -250))
5903132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
5904132718Skan	 (const_int 4)
5905132718Skan	 (if_then_else
5906132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2040))
5907132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
5908132718Skan	   (const_int 6)
5909132718Skan	   (const_int 8)))
5910132718Skan       (if_then_else
5911132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -248))
5912132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
5913132718Skan	 (const_int 6)
5914132718Skan	 (if_then_else
5915132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
5916132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
5917132718Skan	   (const_int 8)
5918132718Skan	   (const_int 10)))))]
5919132718Skan)
5920132718Skan
5921132718Skan(define_insn "*bicsi3_cbranch_scratch"
5922132718Skan  [(set (pc)
5923132718Skan	(if_then_else
5924132718Skan	 (match_operator 4 "equality_operator"
5925132718Skan	  [(and:SI (not:SI (match_operand:SI 2 "s_register_operand" "l"))
5926132718Skan		   (match_operand:SI 1 "s_register_operand" "0"))
5927132718Skan	   (const_int 0)])
5928132718Skan	 (label_ref (match_operand 3 "" ""))
5929132718Skan	 (pc)))
5930132718Skan   (clobber (match_scratch:SI 0 "=l"))]
5931132718Skan  "TARGET_THUMB"
5932132718Skan  "*
5933132718Skan  {
5934132718Skan  output_asm_insn (\"bic\\t%0, %2\", operands);
5935132718Skan  switch (get_attr_length (insn))
5936132718Skan    {
5937132718Skan    case 4:  return \"b%d4\\t%l3\";
5938132718Skan    case 6:  return \"b%D4\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
5939132718Skan    default: return \"b%D4\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
5940132718Skan    }
5941132718Skan  }"
5942132718Skan  [(set (attr "far_jump")
5943132718Skan        (if_then_else
5944132718Skan	    (eq_attr "length" "8")
5945132718Skan	    (const_string "yes")
5946132718Skan            (const_string "no")))
5947132718Skan   (set (attr "length") 
5948132718Skan        (if_then_else
5949132718Skan	    (and (ge (minus (match_dup 3) (pc)) (const_int -250))
5950132718Skan	         (le (minus (match_dup 3) (pc)) (const_int 256)))
5951132718Skan	    (const_int 4)
5952132718Skan	    (if_then_else
5953132718Skan	        (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
5954132718Skan		     (le (minus (match_dup 3) (pc)) (const_int 2048)))
5955132718Skan		(const_int 6)
5956132718Skan		(const_int 8))))]
5957132718Skan)
5958132718Skan  
5959132718Skan(define_insn "*bicsi3_cbranch"
5960132718Skan  [(set (pc)
5961132718Skan	(if_then_else
5962132718Skan	 (match_operator 5 "equality_operator"
5963146895Skan	  [(and:SI (not:SI (match_operand:SI 3 "s_register_operand" "l,l,l,l"))
5964146895Skan		   (match_operand:SI 2 "s_register_operand" "0,1,1,1"))
5965132718Skan	   (const_int 0)])
5966132718Skan	 (label_ref (match_operand 4 "" ""))
5967132718Skan	 (pc)))
5968146895Skan   (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,*?h,*?m,*?m")
5969132718Skan	(and:SI (not:SI (match_dup 3)) (match_dup 2)))
5970146895Skan   (clobber (match_scratch:SI 1 "=X,l,&l,&l"))]
5971132718Skan  "TARGET_THUMB"
5972132718Skan  "*
5973132718Skan  {
5974132718Skan  if (which_alternative == 0)
5975132718Skan    output_asm_insn (\"bic\\t%0, %3\", operands);
5976146895Skan  else if (which_alternative == 1)
5977132718Skan    {
5978132718Skan      output_asm_insn (\"bic\\t%1, %3\", operands);
5979146895Skan      output_asm_insn (\"mov\\t%0, %1\", operands);
5980146895Skan    }
5981132718Skan  else
5982132718Skan    {
5983132718Skan      output_asm_insn (\"bic\\t%1, %3\", operands);
5984132718Skan      output_asm_insn (\"str\\t%1, %0\", operands);
5985132718Skan    }
5986132718Skan
5987132718Skan  switch (get_attr_length (insn) - (which_alternative ? 2 : 0))
5988132718Skan    {
5989132718Skan    case 4:  return \"b%d5\\t%l4\";
5990132718Skan    case 6:  return \"b%D5\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\";
5991132718Skan    default: return \"b%D5\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\";
5992132718Skan    }
5993132718Skan  }"
5994132718Skan  [(set (attr "far_jump")
5995132718Skan        (if_then_else
5996132718Skan	    (ior (and (eq (symbol_ref ("which_alternative"))
5997132718Skan	                  (const_int 0))
5998132718Skan		      (eq_attr "length" "8"))
5999132718Skan		 (eq_attr "length" "10"))
6000132718Skan	    (const_string "yes")
6001132718Skan            (const_string "no")))
6002132718Skan   (set (attr "length")
6003132718Skan     (if_then_else
6004132718Skan       (eq (symbol_ref ("which_alternative"))
6005132718Skan		       (const_int 0))
6006132718Skan       (if_then_else
6007132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -250))
6008132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
6009132718Skan	 (const_int 4)
6010132718Skan	 (if_then_else
6011132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2040))
6012132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
6013132718Skan	   (const_int 6)
6014132718Skan	   (const_int 8)))
6015132718Skan       (if_then_else
6016132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -248))
6017132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
6018132718Skan	 (const_int 6)
6019132718Skan	 (if_then_else
6020132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
6021132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
6022132718Skan	   (const_int 8)
6023132718Skan	   (const_int 10)))))]
6024132718Skan)
6025132718Skan
6026132718Skan(define_insn "*cbranchne_decr1"
6027132718Skan  [(set (pc)
6028132718Skan	(if_then_else (match_operator 3 "equality_operator"
6029132718Skan		       [(match_operand:SI 2 "s_register_operand" "l,l,1,l")
6030132718Skan		        (const_int 0)])
6031132718Skan		      (label_ref (match_operand 4 "" ""))
6032132718Skan		      (pc)))
6033132718Skan   (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,*?h,*?m,*?m")
6034132718Skan	(plus:SI (match_dup 2) (const_int -1)))
6035132718Skan   (clobber (match_scratch:SI 1 "=X,l,&l,&l"))]
6036132718Skan  "TARGET_THUMB"
6037132718Skan  "*
6038132718Skan   {
6039132718Skan     rtx cond[2];
6040132718Skan     cond[0] = gen_rtx_fmt_ee ((GET_CODE (operands[3]) == NE
6041132718Skan				? GEU : LTU),
6042132718Skan			       VOIDmode, operands[2], const1_rtx);
6043132718Skan     cond[1] = operands[4];
6044132718Skan
6045132718Skan     if (which_alternative == 0)
6046132718Skan       output_asm_insn (\"sub\\t%0, %2, #1\", operands);
6047132718Skan     else if (which_alternative == 1)
6048132718Skan       {
6049132718Skan	 /* We must provide an alternative for a hi reg because reload 
6050132718Skan	    cannot handle output reloads on a jump instruction, but we
6051132718Skan	    can't subtract into that.  Fortunately a mov from lo to hi
6052132718Skan	    does not clobber the condition codes.  */
6053132718Skan	 output_asm_insn (\"sub\\t%1, %2, #1\", operands);
6054132718Skan	 output_asm_insn (\"mov\\t%0, %1\", operands);
6055132718Skan       }
6056132718Skan     else
6057132718Skan       {
6058132718Skan	 /* Similarly, but the target is memory.  */
6059132718Skan	 output_asm_insn (\"sub\\t%1, %2, #1\", operands);
6060132718Skan	 output_asm_insn (\"str\\t%1, %0\", operands);
6061132718Skan       }
6062132718Skan
6063132718Skan     switch (get_attr_length (insn) - (which_alternative ? 2 : 0))
6064132718Skan       {
6065132718Skan	 case 4:
6066132718Skan	   output_asm_insn (\"b%d0\\t%l1\", cond);
6067132718Skan	   return \"\";
6068132718Skan	 case 6:
6069132718Skan	   output_asm_insn (\"b%D0\\t.LCB%=\", cond);
6070132718Skan	   return \"b\\t%l4\\t%@long jump\\n.LCB%=:\";
6071132718Skan	 default:
6072132718Skan	   output_asm_insn (\"b%D0\\t.LCB%=\", cond);
6073132718Skan	   return \"bl\\t%l4\\t%@far jump\\n.LCB%=:\";
6074132718Skan       }
6075132718Skan   }
6076132718Skan  "
6077132718Skan  [(set (attr "far_jump")
6078132718Skan        (if_then_else
6079132718Skan	    (ior (and (eq (symbol_ref ("which_alternative"))
6080132718Skan	                  (const_int 0))
6081132718Skan		      (eq_attr "length" "8"))
6082132718Skan		 (eq_attr "length" "10"))
6083132718Skan	    (const_string "yes")
6084132718Skan            (const_string "no")))
6085132718Skan   (set_attr_alternative "length"
6086132718Skan      [
6087132718Skan       ;; Alternative 0
6088132718Skan       (if_then_else
6089132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -250))
6090132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
6091132718Skan	 (const_int 4)
6092132718Skan	 (if_then_else
6093132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2040))
6094132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
6095132718Skan	   (const_int 6)
6096132718Skan	   (const_int 8)))
6097132718Skan       ;; Alternative 1
6098132718Skan       (if_then_else
6099132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -248))
6100132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
6101132718Skan	 (const_int 6)
6102132718Skan	 (if_then_else
6103132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
6104132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
6105132718Skan	   (const_int 8)
6106132718Skan	   (const_int 10)))
6107132718Skan       ;; Alternative 2
6108132718Skan       (if_then_else
6109132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -248))
6110132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
6111132718Skan	 (const_int 6)
6112132718Skan	 (if_then_else
6113132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
6114132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
6115132718Skan	   (const_int 8)
6116132718Skan	   (const_int 10)))
6117132718Skan       ;; Alternative 3
6118132718Skan       (if_then_else
6119132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -248))
6120132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
6121132718Skan	 (const_int 6)
6122132718Skan	 (if_then_else
6123132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2038))
6124132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
6125132718Skan	   (const_int 8)
6126132718Skan	   (const_int 10)))])]
6127132718Skan)
6128132718Skan
6129132718Skan(define_insn "*addsi3_cbranch"
6130132718Skan  [(set (pc)
6131132718Skan	(if_then_else
6132132718Skan	 (match_operator 4 "comparison_operator"
6133132718Skan	  [(plus:SI
6134132718Skan	    (match_operand:SI 2 "s_register_operand" "%l,0,*0,1,1,1")
6135132718Skan	    (match_operand:SI 3 "reg_or_int_operand" "lL,IJ,*r,lIJ,lIJ,lIJ"))
6136132718Skan	   (const_int 0)])
6137132718Skan	 (label_ref (match_operand 5 "" ""))
6138132718Skan	 (pc)))
6139132718Skan   (set
6140132718Skan    (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,l,*!h,*?h,*?m,*?m")
6141132718Skan    (plus:SI (match_dup 2) (match_dup 3)))
6142132718Skan   (clobber (match_scratch:SI 1 "=X,X,X,l,&l,&l"))]
6143132718Skan  "TARGET_THUMB
6144132718Skan   && (GET_CODE (operands[4]) == EQ
6145132718Skan       || GET_CODE (operands[4]) == NE
6146132718Skan       || GET_CODE (operands[4]) == GE
6147132718Skan       || GET_CODE (operands[4]) == LT)"
6148132718Skan  "*
6149132718Skan   {
6150132718Skan     rtx cond[3];
6151132718Skan
6152132718Skan     
6153132718Skan     cond[0] = (which_alternative < 3) ? operands[0] : operands[1];
6154132718Skan     cond[1] = operands[2];
6155132718Skan     cond[2] = operands[3];
6156132718Skan
6157132718Skan     if (GET_CODE (cond[2]) == CONST_INT && INTVAL (cond[2]) < 0)
6158132718Skan       output_asm_insn (\"sub\\t%0, %1, #%n2\", cond);
6159132718Skan     else
6160132718Skan       output_asm_insn (\"add\\t%0, %1, %2\", cond);
6161132718Skan
6162132718Skan     if (which_alternative >= 3
6163132718Skan	 && which_alternative < 4)
6164132718Skan       output_asm_insn (\"mov\\t%0, %1\", operands);
6165132718Skan     else if (which_alternative >= 4)
6166132718Skan       output_asm_insn (\"str\\t%1, %0\", operands);
6167132718Skan
6168132718Skan     switch (get_attr_length (insn) - ((which_alternative >= 3) ? 2 : 0))
6169132718Skan       {
6170132718Skan	 case 4:
6171132718Skan	   return \"b%d4\\t%l5\";
6172132718Skan	 case 6:
6173132718Skan	   return \"b%D4\\t.LCB%=\;b\\t%l5\\t%@long jump\\n.LCB%=:\";
6174132718Skan	 default:
6175132718Skan	   return \"b%D4\\t.LCB%=\;bl\\t%l5\\t%@far jump\\n.LCB%=:\";
6176132718Skan       }
6177132718Skan   }
6178132718Skan  "
6179132718Skan  [(set (attr "far_jump")
6180132718Skan        (if_then_else
6181132718Skan	    (ior (and (lt (symbol_ref ("which_alternative"))
6182132718Skan	                  (const_int 3))
6183132718Skan		      (eq_attr "length" "8"))
6184132718Skan		 (eq_attr "length" "10"))
6185132718Skan	    (const_string "yes")
6186132718Skan            (const_string "no")))
6187132718Skan   (set (attr "length")
6188132718Skan     (if_then_else
6189132718Skan       (lt (symbol_ref ("which_alternative"))
6190132718Skan		       (const_int 3))
6191132718Skan       (if_then_else
6192132718Skan	 (and (ge (minus (match_dup 5) (pc)) (const_int -250))
6193132718Skan	      (le (minus (match_dup 5) (pc)) (const_int 256)))
6194132718Skan	 (const_int 4)
6195132718Skan	 (if_then_else
6196132718Skan	   (and (ge (minus (match_dup 5) (pc)) (const_int -2040))
6197132718Skan		(le (minus (match_dup 5) (pc)) (const_int 2048)))
6198132718Skan	   (const_int 6)
6199132718Skan	   (const_int 8)))
6200132718Skan       (if_then_else
6201132718Skan	 (and (ge (minus (match_dup 5) (pc)) (const_int -248))
6202132718Skan	      (le (minus (match_dup 5) (pc)) (const_int 256)))
6203132718Skan	 (const_int 6)
6204132718Skan	 (if_then_else
6205132718Skan	   (and (ge (minus (match_dup 5) (pc)) (const_int -2038))
6206132718Skan		(le (minus (match_dup 5) (pc)) (const_int 2048)))
6207132718Skan	   (const_int 8)
6208132718Skan	   (const_int 10)))))]
6209132718Skan)
6210132718Skan
6211132718Skan(define_insn "*addsi3_cbranch_scratch"
6212132718Skan  [(set (pc)
6213132718Skan	(if_then_else
6214132718Skan	 (match_operator 3 "comparison_operator"
6215132718Skan	  [(plus:SI
6216132718Skan	    (match_operand:SI 1 "s_register_operand" "%l,l,l,0")
6217132718Skan	    (match_operand:SI 2 "reg_or_int_operand" "J,l,I,L"))
6218132718Skan	   (const_int 0)])
6219132718Skan	 (label_ref (match_operand 4 "" ""))
6220132718Skan	 (pc)))
6221132718Skan   (clobber (match_scratch:SI 0 "=X,X,l,l"))]
6222132718Skan  "TARGET_THUMB
6223132718Skan   && (GET_CODE (operands[3]) == EQ
6224132718Skan       || GET_CODE (operands[3]) == NE
6225132718Skan       || GET_CODE (operands[3]) == GE
6226132718Skan       || GET_CODE (operands[3]) == LT)"
6227132718Skan  "*
6228132718Skan   {
6229132718Skan     switch (which_alternative)
6230132718Skan       {
6231132718Skan       case 0:
6232132718Skan	 output_asm_insn (\"cmp\t%1, #%n2\", operands);
6233132718Skan	 break;
6234132718Skan       case 1:
6235132718Skan	 output_asm_insn (\"cmn\t%1, %2\", operands);
6236132718Skan	 break;
6237132718Skan       case 3:
6238132718Skan	 output_asm_insn (\"add\t%0, %1, %2\", operands);
6239146895Skan	 break;
6240132718Skan       case 4:
6241132718Skan	 output_asm_insn (\"add\t%0, %0, %2\", operands);
6242146895Skan	 break;
6243132718Skan       }
6244132718Skan
6245132718Skan     switch (get_attr_length (insn))
6246132718Skan       {
6247132718Skan	 case 4:
6248132718Skan	   return \"b%d3\\t%l4\";
6249132718Skan	 case 6:
6250132718Skan	   return \"b%D3\\t.LCB%=\;b\\t%l4\\t%@long jump\\n.LCB%=:\";
6251132718Skan	 default:
6252132718Skan	   return \"b%D3\\t.LCB%=\;bl\\t%l4\\t%@far jump\\n.LCB%=:\";
6253132718Skan       }
6254132718Skan   }
6255132718Skan  "
6256132718Skan  [(set (attr "far_jump")
6257132718Skan        (if_then_else
6258132718Skan	    (eq_attr "length" "8")
6259132718Skan	    (const_string "yes")
6260132718Skan            (const_string "no")))
6261132718Skan   (set (attr "length")
6262132718Skan       (if_then_else
6263132718Skan	 (and (ge (minus (match_dup 4) (pc)) (const_int -250))
6264132718Skan	      (le (minus (match_dup 4) (pc)) (const_int 256)))
6265132718Skan	 (const_int 4)
6266132718Skan	 (if_then_else
6267132718Skan	   (and (ge (minus (match_dup 4) (pc)) (const_int -2040))
6268132718Skan		(le (minus (match_dup 4) (pc)) (const_int 2048)))
6269132718Skan	   (const_int 6)
6270132718Skan	   (const_int 8))))]
6271132718Skan)
6272132718Skan
6273132718Skan(define_insn "*subsi3_cbranch"
6274132718Skan  [(set (pc)
6275132718Skan	(if_then_else
6276132718Skan	 (match_operator 4 "comparison_operator"
6277132718Skan	  [(minus:SI
6278132718Skan	    (match_operand:SI 2 "s_register_operand" "l,l,1,l")
6279132718Skan	    (match_operand:SI 3 "s_register_operand" "l,l,l,l"))
6280132718Skan	   (const_int 0)])
6281132718Skan	 (label_ref (match_operand 5 "" ""))
6282132718Skan	 (pc)))
6283132718Skan   (set (match_operand:SI 0 "thumb_cbrch_target_operand" "=l,*?h,*?m,*?m")
6284132718Skan	(minus:SI (match_dup 2) (match_dup 3)))
6285132718Skan   (clobber (match_scratch:SI 1 "=X,l,&l,&l"))]
6286132718Skan  "TARGET_THUMB
6287132718Skan   && (GET_CODE (operands[4]) == EQ
6288132718Skan       || GET_CODE (operands[4]) == NE
6289132718Skan       || GET_CODE (operands[4]) == GE
6290132718Skan       || GET_CODE (operands[4]) == LT)"
6291132718Skan  "*
6292132718Skan   {
6293132718Skan     if (which_alternative == 0)
6294132718Skan       output_asm_insn (\"sub\\t%0, %2, %3\", operands);
6295132718Skan     else if (which_alternative == 1)
6296132718Skan       {
6297132718Skan	 /* We must provide an alternative for a hi reg because reload 
6298132718Skan	    cannot handle output reloads on a jump instruction, but we
6299132718Skan	    can't subtract into that.  Fortunately a mov from lo to hi
6300132718Skan	    does not clobber the condition codes.  */
6301132718Skan	 output_asm_insn (\"sub\\t%1, %2, %3\", operands);
6302132718Skan	 output_asm_insn (\"mov\\t%0, %1\", operands);
6303132718Skan       }
6304132718Skan     else
6305132718Skan       {
6306132718Skan	 /* Similarly, but the target is memory.  */
6307132718Skan	 output_asm_insn (\"sub\\t%1, %2, %3\", operands);
6308132718Skan	 output_asm_insn (\"str\\t%1, %0\", operands);
6309132718Skan       }
6310132718Skan
6311132718Skan     switch (get_attr_length (insn) - ((which_alternative != 0) ? 2 : 0))
6312132718Skan       {
6313132718Skan	 case 4:
6314132718Skan	   return \"b%d4\\t%l5\";
6315132718Skan	 case 6:
6316132718Skan	   return \"b%D4\\t.LCB%=\;b\\t%l5\\t%@long jump\\n.LCB%=:\";
6317132718Skan	 default:
6318132718Skan	   return \"b%D4\\t.LCB%=\;bl\\t%l5\\t%@far jump\\n.LCB%=:\";
6319132718Skan       }
6320132718Skan   }
6321132718Skan  "
6322132718Skan  [(set (attr "far_jump")
6323132718Skan        (if_then_else
6324132718Skan	    (ior (and (eq (symbol_ref ("which_alternative"))
6325132718Skan	                  (const_int 0))
6326132718Skan		      (eq_attr "length" "8"))
6327132718Skan		 (eq_attr "length" "10"))
6328132718Skan	    (const_string "yes")
6329132718Skan            (const_string "no")))
6330132718Skan   (set (attr "length")
6331132718Skan     (if_then_else
6332132718Skan       (eq (symbol_ref ("which_alternative"))
6333132718Skan		       (const_int 0))
6334132718Skan       (if_then_else
6335132718Skan	 (and (ge (minus (match_dup 5) (pc)) (const_int -250))
6336132718Skan	      (le (minus (match_dup 5) (pc)) (const_int 256)))
6337132718Skan	 (const_int 4)
6338132718Skan	 (if_then_else
6339132718Skan	   (and (ge (minus (match_dup 5) (pc)) (const_int -2040))
6340132718Skan		(le (minus (match_dup 5) (pc)) (const_int 2048)))
6341132718Skan	   (const_int 6)
6342132718Skan	   (const_int 8)))
6343132718Skan       (if_then_else
6344132718Skan	 (and (ge (minus (match_dup 5) (pc)) (const_int -248))
6345132718Skan	      (le (minus (match_dup 5) (pc)) (const_int 256)))
6346132718Skan	 (const_int 6)
6347132718Skan	 (if_then_else
6348132718Skan	   (and (ge (minus (match_dup 5) (pc)) (const_int -2038))
6349132718Skan		(le (minus (match_dup 5) (pc)) (const_int 2048)))
6350132718Skan	   (const_int 8)
6351132718Skan	   (const_int 10)))))]
6352132718Skan)
6353132718Skan
6354132718Skan(define_insn "*subsi3_cbranch_scratch"
6355132718Skan  [(set (pc)
6356132718Skan	(if_then_else
6357132718Skan	 (match_operator 0 "arm_comparison_operator"
6358132718Skan	  [(minus:SI (match_operand:SI 1 "register_operand" "l")
6359132718Skan		     (match_operand:SI 2 "nonmemory_operand" "l"))
6360132718Skan	   (const_int 0)])
6361132718Skan	 (label_ref (match_operand 3 "" ""))
6362132718Skan	 (pc)))]
6363132718Skan  "TARGET_THUMB
6364132718Skan   && (GET_CODE (operands[0]) == EQ
6365132718Skan       || GET_CODE (operands[0]) == NE
6366132718Skan       || GET_CODE (operands[0]) == GE
6367132718Skan       || GET_CODE (operands[0]) == LT)"
6368132718Skan  "*
6369132718Skan  output_asm_insn (\"cmp\\t%1, %2\", operands);
6370132718Skan  switch (get_attr_length (insn))
6371132718Skan    {
6372132718Skan    case 4:  return \"b%d0\\t%l3\";
6373132718Skan    case 6:  return \"b%D0\\t.LCB%=\;b\\t%l3\\t%@long jump\\n.LCB%=:\";
6374132718Skan    default: return \"b%D0\\t.LCB%=\;bl\\t%l3\\t%@far jump\\n.LCB%=:\";
6375132718Skan    }
6376132718Skan  "
6377132718Skan  [(set (attr "far_jump")
6378132718Skan        (if_then_else
6379132718Skan	    (eq_attr "length" "8")
6380132718Skan	    (const_string "yes")
6381132718Skan            (const_string "no")))
6382132718Skan   (set (attr "length") 
6383132718Skan        (if_then_else
6384132718Skan	    (and (ge (minus (match_dup 3) (pc)) (const_int -250))
6385132718Skan	         (le (minus (match_dup 3) (pc)) (const_int 256)))
6386132718Skan	    (const_int 4)
6387132718Skan	    (if_then_else
6388132718Skan	        (and (ge (minus (match_dup 3) (pc)) (const_int -2040))
6389132718Skan		     (le (minus (match_dup 3) (pc)) (const_int 2048)))
6390132718Skan		(const_int 6)
6391132718Skan		(const_int 8))))]
6392132718Skan)
6393132718Skan
6394132718Skan;; Comparison and test insns
6395132718Skan
639690075Sobrien(define_expand "cmpsi"
639790075Sobrien  [(match_operand:SI 0 "s_register_operand" "")
639890075Sobrien   (match_operand:SI 1 "arm_add_operand" "")]
639990075Sobrien  "TARGET_ARM"
640090075Sobrien  "{
640190075Sobrien    arm_compare_op0 = operands[0];
640290075Sobrien    arm_compare_op1 = operands[1];
640390075Sobrien    DONE;
640490075Sobrien  }"
640590075Sobrien)
640690075Sobrien
640790075Sobrien(define_expand "cmpsf"
640890075Sobrien  [(match_operand:SF 0 "s_register_operand" "")
640990075Sobrien   (match_operand:SF 1 "fpa_rhs_operand" "")]
641090075Sobrien  "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
6411132718Skan  "
6412132718Skan  if (TARGET_CIRRUS && !cirrus_fp_register (operands[1], SFmode))
641390075Sobrien    operands[1] = force_reg (SFmode, operands[1]);
6414132718Skan
6415132718Skan  arm_compare_op0 = operands[0];
6416132718Skan  arm_compare_op1 = operands[1];
641790075Sobrien  DONE;
641890075Sobrien  "
641990075Sobrien)
642090075Sobrien
642190075Sobrien(define_expand "cmpdf"
642290075Sobrien  [(match_operand:DF 0 "s_register_operand" "")
642390075Sobrien   (match_operand:DF 1 "fpa_rhs_operand" "")]
642490075Sobrien  "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
6425132718Skan  "
6426132718Skan  if (TARGET_CIRRUS && !cirrus_fp_register (operands[1], DFmode))
642790075Sobrien    operands[1] = force_reg (DFmode, operands[1]);
6428132718Skan
6429132718Skan  arm_compare_op0 = operands[0];
643090075Sobrien  arm_compare_op1 = operands[1];
643190075Sobrien  DONE;
643290075Sobrien  "
643390075Sobrien)
643490075Sobrien
643590075Sobrien(define_insn "*arm_cmpsi_insn"
643690075Sobrien  [(set (reg:CC CC_REGNUM)
643790075Sobrien	(compare:CC (match_operand:SI 0 "s_register_operand" "r,r")
643890075Sobrien		    (match_operand:SI 1 "arm_add_operand"    "rI,L")))]
643990075Sobrien  "TARGET_ARM"
644090075Sobrien  "@
644190075Sobrien   cmp%?\\t%0, %1
644290075Sobrien   cmn%?\\t%0, #%n1"
644390075Sobrien  [(set_attr "conds" "set")]
644490075Sobrien)
644590075Sobrien
644690075Sobrien(define_insn "*cmpsi_shiftsi"
644790075Sobrien  [(set (reg:CC CC_REGNUM)
644890075Sobrien	(compare:CC (match_operand:SI   0 "s_register_operand" "r")
644990075Sobrien		    (match_operator:SI  3 "shift_operator"
645090075Sobrien		     [(match_operand:SI 1 "s_register_operand" "r")
645190075Sobrien		      (match_operand:SI 2 "arm_rhs_operand"    "rM")])))]
645290075Sobrien  "TARGET_ARM"
645390075Sobrien  "cmp%?\\t%0, %1%S3"
645490075Sobrien  [(set_attr "conds" "set")
645590075Sobrien   (set_attr "shift" "1")
645690075Sobrien   ]
645790075Sobrien)
645890075Sobrien
645990075Sobrien(define_insn "*cmpsi_shiftsi_swp"
646090075Sobrien  [(set (reg:CC_SWP CC_REGNUM)
646190075Sobrien	(compare:CC_SWP (match_operator:SI 3 "shift_operator"
646290075Sobrien			 [(match_operand:SI 1 "s_register_operand" "r")
646390075Sobrien			  (match_operand:SI 2 "reg_or_int_operand" "rM")])
646490075Sobrien			(match_operand:SI 0 "s_register_operand" "r")))]
646590075Sobrien  "TARGET_ARM"
646690075Sobrien  "cmp%?\\t%0, %1%S3"
646790075Sobrien  [(set_attr "conds" "set")
646890075Sobrien   (set_attr "shift" "1")
646990075Sobrien   ]
647090075Sobrien)
647190075Sobrien
647290075Sobrien(define_insn "*cmpsi_neg_shiftsi"
647390075Sobrien  [(set (reg:CC CC_REGNUM)
647490075Sobrien	(compare:CC (match_operand:SI 0 "s_register_operand" "r")
647590075Sobrien		    (neg:SI (match_operator:SI 3 "shift_operator"
647690075Sobrien			     [(match_operand:SI 1 "s_register_operand" "r")
647790075Sobrien			      (match_operand:SI 2 "arm_rhs_operand" "rM")]))))]
647890075Sobrien  "TARGET_ARM"
647990075Sobrien  "cmn%?\\t%0, %1%S3"
648090075Sobrien  [(set_attr "conds" "set")
648190075Sobrien   (set_attr "shift" "1")
648290075Sobrien   ]
648390075Sobrien)
648490075Sobrien
648590075Sobrien;; Cirrus SF compare instruction
648690075Sobrien(define_insn "*cirrus_cmpsf"
6487132718Skan  [(set (reg:CCFP CC_REGNUM)
6488132718Skan	(compare:CCFP (match_operand:SF 0 "cirrus_fp_register" "v")
648990075Sobrien		      (match_operand:SF 1 "cirrus_fp_register" "v")))]
6490132718Skan  "TARGET_ARM && TARGET_CIRRUS"
6491132718Skan  "cfcmps%?\\tr15, %V0, %V1"
6492132718Skan  [(set_attr "type"   "mav_farith")
6493132718Skan   (set_attr "cirrus" "compare")]
6494132718Skan)
6495132718Skan
649690075Sobrien;; Cirrus DF compare instruction
649790075Sobrien(define_insn "*cirrus_cmpdf"
6498132718Skan  [(set (reg:CCFP CC_REGNUM)
6499132718Skan	(compare:CCFP (match_operand:DF 0 "cirrus_fp_register" "v")
650090075Sobrien		      (match_operand:DF 1 "cirrus_fp_register" "v")))]
6501132718Skan  "TARGET_ARM && TARGET_CIRRUS"
6502132718Skan  "cfcmpd%?\\tr15, %V0, %V1"
6503132718Skan  [(set_attr "type"   "mav_farith")
6504132718Skan   (set_attr "cirrus" "compare")]
6505132718Skan)
6506132718Skan
650790075Sobrien;; Cirrus DI compare instruction
650890075Sobrien(define_expand "cmpdi"
6509132718Skan  [(match_operand:DI 0 "cirrus_fp_register" "")
6510132718Skan   (match_operand:DI 1 "cirrus_fp_register" "")]
6511132718Skan  "TARGET_ARM && TARGET_CIRRUS"
6512132718Skan  "{
6513132718Skan     arm_compare_op0 = operands[0];
6514132718Skan     arm_compare_op1 = operands[1];
6515132718Skan     DONE;
6516132718Skan   }")
6517132718Skan
6518132718Skan(define_insn "*cirrus_cmpdi"
651990075Sobrien  [(set (reg:CC CC_REGNUM)
6520132718Skan	(compare:CC (match_operand:DI 0 "cirrus_fp_register" "v")
6521132718Skan		    (match_operand:DI 1 "cirrus_fp_register" "v")))]
6522132718Skan  "TARGET_ARM && TARGET_CIRRUS"
6523132718Skan  "cfcmp64%?\\tr15, %V0, %V1"
6524132718Skan  [(set_attr "type"   "mav_farith")
6525132718Skan   (set_attr "cirrus" "compare")]
6526132718Skan)
6527132718Skan
652890075Sobrien; This insn allows redundant compares to be removed by cse, nothing should
652990075Sobrien; ever appear in the output file since (set (reg x) (reg x)) is a no-op that
653090075Sobrien; is deleted later on. The match_dup will match the mode here, so that
653190075Sobrien; mode changes of the condition codes aren't lost by this even though we don't
653290075Sobrien; specify what they are.
653390075Sobrien
653490075Sobrien(define_insn "*deleted_compare"
653590075Sobrien  [(set (match_operand 0 "cc_register" "") (match_dup 0))]
653690075Sobrien  "TARGET_ARM"
653790075Sobrien  "\\t%@ deleted compare"
653890075Sobrien  [(set_attr "conds" "set")
653990075Sobrien   (set_attr "length" "0")]
654090075Sobrien)
654190075Sobrien
654290075Sobrien
654390075Sobrien;; Conditional branch insns
654490075Sobrien
654590075Sobrien(define_expand "beq"
654690075Sobrien  [(set (pc)
654790075Sobrien	(if_then_else (eq (match_dup 1) (const_int 0))
654890075Sobrien		      (label_ref (match_operand 0 "" ""))
654990075Sobrien		      (pc)))]
655090075Sobrien  "TARGET_ARM"
655190075Sobrien  "operands[1] = arm_gen_compare_reg (EQ, arm_compare_op0, arm_compare_op1);"
655290075Sobrien)
655390075Sobrien
655490075Sobrien(define_expand "bne"
655590075Sobrien  [(set (pc)
655690075Sobrien	(if_then_else (ne (match_dup 1) (const_int 0))
655790075Sobrien		      (label_ref (match_operand 0 "" ""))
655890075Sobrien		      (pc)))]
655990075Sobrien  "TARGET_ARM"
656090075Sobrien  "operands[1] = arm_gen_compare_reg (NE, arm_compare_op0, arm_compare_op1);"
656190075Sobrien)
656290075Sobrien
656390075Sobrien(define_expand "bgt"
656490075Sobrien  [(set (pc)
656590075Sobrien	(if_then_else (gt (match_dup 1) (const_int 0))
656690075Sobrien		      (label_ref (match_operand 0 "" ""))
656790075Sobrien		      (pc)))]
656890075Sobrien  "TARGET_ARM"
656990075Sobrien  "operands[1] = arm_gen_compare_reg (GT, arm_compare_op0, arm_compare_op1);"
657090075Sobrien)
657190075Sobrien
657290075Sobrien(define_expand "ble"
657390075Sobrien  [(set (pc)
657490075Sobrien	(if_then_else (le (match_dup 1) (const_int 0))
657590075Sobrien		      (label_ref (match_operand 0 "" ""))
657690075Sobrien		      (pc)))]
657790075Sobrien  "TARGET_ARM"
657890075Sobrien  "operands[1] = arm_gen_compare_reg (LE, arm_compare_op0, arm_compare_op1);"
657990075Sobrien)
658090075Sobrien
658190075Sobrien(define_expand "bge"
658290075Sobrien  [(set (pc)
658390075Sobrien	(if_then_else (ge (match_dup 1) (const_int 0))
658490075Sobrien		      (label_ref (match_operand 0 "" ""))
658590075Sobrien		      (pc)))]
658690075Sobrien  "TARGET_ARM"
658790075Sobrien  "operands[1] = arm_gen_compare_reg (GE, arm_compare_op0, arm_compare_op1);"
658890075Sobrien)
658990075Sobrien
659090075Sobrien(define_expand "blt"
659190075Sobrien  [(set (pc)
659290075Sobrien	(if_then_else (lt (match_dup 1) (const_int 0))
659390075Sobrien		      (label_ref (match_operand 0 "" ""))
659490075Sobrien		      (pc)))]
659590075Sobrien  "TARGET_ARM"
659690075Sobrien  "operands[1] = arm_gen_compare_reg (LT, arm_compare_op0, arm_compare_op1);"
659790075Sobrien)
659890075Sobrien
659990075Sobrien(define_expand "bgtu"
660090075Sobrien  [(set (pc)
660190075Sobrien	(if_then_else (gtu (match_dup 1) (const_int 0))
660290075Sobrien		      (label_ref (match_operand 0 "" ""))
660390075Sobrien		      (pc)))]
660490075Sobrien  "TARGET_ARM"
660590075Sobrien  "operands[1] = arm_gen_compare_reg (GTU, arm_compare_op0, arm_compare_op1);"
660690075Sobrien)
660790075Sobrien
660890075Sobrien(define_expand "bleu"
660990075Sobrien  [(set (pc)
661090075Sobrien	(if_then_else (leu (match_dup 1) (const_int 0))
661190075Sobrien		      (label_ref (match_operand 0 "" ""))
661290075Sobrien		      (pc)))]
661390075Sobrien  "TARGET_ARM"
661490075Sobrien  "operands[1] = arm_gen_compare_reg (LEU, arm_compare_op0, arm_compare_op1);"
661590075Sobrien)
661690075Sobrien
661790075Sobrien(define_expand "bgeu"
661890075Sobrien  [(set (pc)
661990075Sobrien	(if_then_else (geu (match_dup 1) (const_int 0))
662090075Sobrien		      (label_ref (match_operand 0 "" ""))
662190075Sobrien		      (pc)))]
662290075Sobrien  "TARGET_ARM"
662390075Sobrien  "operands[1] = arm_gen_compare_reg (GEU, arm_compare_op0, arm_compare_op1);"
662490075Sobrien)
662590075Sobrien
662690075Sobrien(define_expand "bltu"
662790075Sobrien  [(set (pc)
662890075Sobrien	(if_then_else (ltu (match_dup 1) (const_int 0))
662990075Sobrien		      (label_ref (match_operand 0 "" ""))
663090075Sobrien		      (pc)))]
663190075Sobrien  "TARGET_ARM"
663290075Sobrien  "operands[1] = arm_gen_compare_reg (LTU, arm_compare_op0, arm_compare_op1);"
663390075Sobrien)
663490075Sobrien
663590075Sobrien(define_expand "bunordered"
663690075Sobrien  [(set (pc)
663790075Sobrien	(if_then_else (unordered (match_dup 1) (const_int 0))
663890075Sobrien		      (label_ref (match_operand 0 "" ""))
663990075Sobrien		      (pc)))]
664090075Sobrien  "TARGET_ARM && TARGET_HARD_FLOAT"
664190075Sobrien  "operands[1] = arm_gen_compare_reg (UNORDERED, arm_compare_op0,
664290075Sobrien				      arm_compare_op1);"
664390075Sobrien)
664490075Sobrien
664590075Sobrien(define_expand "bordered"
664690075Sobrien  [(set (pc)
664790075Sobrien	(if_then_else (ordered (match_dup 1) (const_int 0))
664890075Sobrien		      (label_ref (match_operand 0 "" ""))
664990075Sobrien		      (pc)))]
665090075Sobrien  "TARGET_ARM && TARGET_HARD_FLOAT"
665190075Sobrien  "operands[1] = arm_gen_compare_reg (ORDERED, arm_compare_op0,
665290075Sobrien				      arm_compare_op1);"
665390075Sobrien)
665490075Sobrien
665590075Sobrien(define_expand "bungt"
665690075Sobrien  [(set (pc)
665790075Sobrien	(if_then_else (ungt (match_dup 1) (const_int 0))
665890075Sobrien		      (label_ref (match_operand 0 "" ""))
665990075Sobrien		      (pc)))]
666090075Sobrien  "TARGET_ARM && TARGET_HARD_FLOAT"
666190075Sobrien  "operands[1] = arm_gen_compare_reg (UNGT, arm_compare_op0, arm_compare_op1);"
666290075Sobrien)
666390075Sobrien
666490075Sobrien(define_expand "bunlt"
666590075Sobrien  [(set (pc)
666690075Sobrien	(if_then_else (unlt (match_dup 1) (const_int 0))
666790075Sobrien		      (label_ref (match_operand 0 "" ""))
666890075Sobrien		      (pc)))]
666990075Sobrien  "TARGET_ARM && TARGET_HARD_FLOAT"
667090075Sobrien  "operands[1] = arm_gen_compare_reg (UNLT, arm_compare_op0, arm_compare_op1);"
667190075Sobrien)
667290075Sobrien
667390075Sobrien(define_expand "bunge"
667490075Sobrien  [(set (pc)
667590075Sobrien	(if_then_else (unge (match_dup 1) (const_int 0))
667690075Sobrien		      (label_ref (match_operand 0 "" ""))
667790075Sobrien		      (pc)))]
667890075Sobrien  "TARGET_ARM && TARGET_HARD_FLOAT"
667990075Sobrien  "operands[1] = arm_gen_compare_reg (UNGE, arm_compare_op0, arm_compare_op1);"
668090075Sobrien)
668190075Sobrien
668290075Sobrien(define_expand "bunle"
668390075Sobrien  [(set (pc)
668490075Sobrien	(if_then_else (unle (match_dup 1) (const_int 0))
668590075Sobrien		      (label_ref (match_operand 0 "" ""))
668690075Sobrien		      (pc)))]
668790075Sobrien  "TARGET_ARM && TARGET_HARD_FLOAT"
668890075Sobrien  "operands[1] = arm_gen_compare_reg (UNLE, arm_compare_op0, arm_compare_op1);"
668990075Sobrien)
669090075Sobrien
669190075Sobrien;; The following two patterns need two branch instructions, since there is
669290075Sobrien;; no single instruction that will handle all cases.
669390075Sobrien(define_expand "buneq"
669490075Sobrien  [(set (pc)
669590075Sobrien	(if_then_else (uneq (match_dup 1) (const_int 0))
669690075Sobrien		      (label_ref (match_operand 0 "" ""))
669790075Sobrien		      (pc)))]
669890075Sobrien  "TARGET_ARM && TARGET_HARD_FLOAT"
669990075Sobrien  "operands[1] = arm_gen_compare_reg (UNEQ, arm_compare_op0, arm_compare_op1);"
670090075Sobrien)
670190075Sobrien
670290075Sobrien(define_expand "bltgt"
670390075Sobrien  [(set (pc)
670490075Sobrien	(if_then_else (ltgt (match_dup 1) (const_int 0))
670590075Sobrien		      (label_ref (match_operand 0 "" ""))
670690075Sobrien		      (pc)))]
670790075Sobrien  "TARGET_ARM && TARGET_HARD_FLOAT"
670890075Sobrien  "operands[1] = arm_gen_compare_reg (LTGT, arm_compare_op0, arm_compare_op1);"
670990075Sobrien)
671090075Sobrien
671190075Sobrien;;
671290075Sobrien;; Patterns to match conditional branch insns.
671390075Sobrien;;
671490075Sobrien
671590075Sobrien; Special pattern to match UNEQ.
671690075Sobrien(define_insn "*arm_buneq"
671790075Sobrien  [(set (pc)
671890075Sobrien	(if_then_else (uneq (match_operand 1 "cc_register" "") (const_int 0))
671990075Sobrien		      (label_ref (match_operand 0 "" ""))
672090075Sobrien		      (pc)))]
672190075Sobrien  "TARGET_ARM && TARGET_HARD_FLOAT"
672290075Sobrien  "*
672390075Sobrien  if (arm_ccfsm_state != 0)
672490075Sobrien    abort ();
672590075Sobrien
672690075Sobrien  return \"bvs\\t%l0\;beq\\t%l0\";
672790075Sobrien  "
6728117395Skan  [(set_attr "conds" "jump_clob")
672990075Sobrien   (set_attr "length" "8")]
673090075Sobrien)
673190075Sobrien
673290075Sobrien; Special pattern to match LTGT.
673390075Sobrien(define_insn "*arm_bltgt"
673490075Sobrien  [(set (pc)
673590075Sobrien	(if_then_else (ltgt (match_operand 1 "cc_register" "") (const_int 0))
673690075Sobrien		      (label_ref (match_operand 0 "" ""))
673790075Sobrien		      (pc)))]
673890075Sobrien  "TARGET_ARM && TARGET_HARD_FLOAT"
673990075Sobrien  "*
674090075Sobrien  if (arm_ccfsm_state != 0)
674190075Sobrien    abort ();
674290075Sobrien
674390075Sobrien  return \"bmi\\t%l0\;bgt\\t%l0\";
674490075Sobrien  "
6745117395Skan  [(set_attr "conds" "jump_clob")
674690075Sobrien   (set_attr "length" "8")]
674790075Sobrien)
674890075Sobrien
674990075Sobrien(define_insn "*arm_cond_branch"
675090075Sobrien  [(set (pc)
675190075Sobrien	(if_then_else (match_operator 1 "arm_comparison_operator"
675290075Sobrien		       [(match_operand 2 "cc_register" "") (const_int 0)])
675390075Sobrien		      (label_ref (match_operand 0 "" ""))
675490075Sobrien		      (pc)))]
675590075Sobrien  "TARGET_ARM"
675690075Sobrien  "*
675790075Sobrien  if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2)
675890075Sobrien    {
675990075Sobrien      arm_ccfsm_state += 2;
676090075Sobrien      return \"\";
676190075Sobrien    }
676290075Sobrien  return \"b%d1\\t%l0\";
676390075Sobrien  "
676490075Sobrien  [(set_attr "conds" "use")]
676590075Sobrien)
676690075Sobrien
676790075Sobrien; Special pattern to match reversed UNEQ.
676890075Sobrien(define_insn "*arm_buneq_reversed"
676990075Sobrien  [(set (pc)
677090075Sobrien	(if_then_else (uneq (match_operand 1 "cc_register" "") (const_int 0))
677190075Sobrien		      (pc)
677290075Sobrien		      (label_ref (match_operand 0 "" ""))))]
677390075Sobrien  "TARGET_ARM && TARGET_HARD_FLOAT"
677490075Sobrien  "*
677590075Sobrien  if (arm_ccfsm_state != 0)
677690075Sobrien    abort ();
677790075Sobrien
677890075Sobrien  return \"bmi\\t%l0\;bgt\\t%l0\";
677990075Sobrien  "
6780117395Skan  [(set_attr "conds" "jump_clob")
678190075Sobrien   (set_attr "length" "8")]
678290075Sobrien)
678390075Sobrien
678490075Sobrien; Special pattern to match reversed LTGT.
678590075Sobrien(define_insn "*arm_bltgt_reversed"
678690075Sobrien  [(set (pc)
678790075Sobrien	(if_then_else (ltgt (match_operand 1 "cc_register" "") (const_int 0))
678890075Sobrien		      (pc)
678990075Sobrien		      (label_ref (match_operand 0 "" ""))))]
679090075Sobrien  "TARGET_ARM && TARGET_HARD_FLOAT"
679190075Sobrien  "*
679290075Sobrien  if (arm_ccfsm_state != 0)
679390075Sobrien    abort ();
679490075Sobrien
679590075Sobrien  return \"bvs\\t%l0\;beq\\t%l0\";
679690075Sobrien  "
6797117395Skan  [(set_attr "conds" "jump_clob")
679890075Sobrien   (set_attr "length" "8")]
679990075Sobrien)
680090075Sobrien
680190075Sobrien(define_insn "*arm_cond_branch_reversed"
680290075Sobrien  [(set (pc)
680390075Sobrien	(if_then_else (match_operator 1 "arm_comparison_operator"
680490075Sobrien		       [(match_operand 2 "cc_register" "") (const_int 0)])
680590075Sobrien		      (pc)
680690075Sobrien		      (label_ref (match_operand 0 "" ""))))]
680790075Sobrien  "TARGET_ARM"
680890075Sobrien  "*
680990075Sobrien  if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2)
681090075Sobrien    {
681190075Sobrien      arm_ccfsm_state += 2;
681290075Sobrien      return \"\";
681390075Sobrien    }
681490075Sobrien  return \"b%D1\\t%l0\";
681590075Sobrien  "
681690075Sobrien  [(set_attr "conds" "use")]
681790075Sobrien)
681890075Sobrien
681990075Sobrien
682090075Sobrien
682190075Sobrien; scc insns
682290075Sobrien
682390075Sobrien(define_expand "seq"
682490075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
682590075Sobrien	(eq:SI (match_dup 1) (const_int 0)))]
6826132718Skan  "TARGET_ARM"
682790075Sobrien  "operands[1] = arm_gen_compare_reg (EQ, arm_compare_op0, arm_compare_op1);"
682890075Sobrien)
682990075Sobrien
683090075Sobrien(define_expand "sne"
683190075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
683290075Sobrien	(ne:SI (match_dup 1) (const_int 0)))]
6833132718Skan  "TARGET_ARM"
683490075Sobrien  "operands[1] = arm_gen_compare_reg (NE, arm_compare_op0, arm_compare_op1);"
683590075Sobrien)
683690075Sobrien
683790075Sobrien(define_expand "sgt"
683890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
683990075Sobrien	(gt:SI (match_dup 1) (const_int 0)))]
6840132718Skan  "TARGET_ARM"
684190075Sobrien  "operands[1] = arm_gen_compare_reg (GT, arm_compare_op0, arm_compare_op1);"
684290075Sobrien)
684390075Sobrien
684490075Sobrien(define_expand "sle"
684590075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
684690075Sobrien	(le:SI (match_dup 1) (const_int 0)))]
6847132718Skan  "TARGET_ARM"
684890075Sobrien  "operands[1] = arm_gen_compare_reg (LE, arm_compare_op0, arm_compare_op1);"
684990075Sobrien)
685090075Sobrien
685190075Sobrien(define_expand "sge"
685290075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
685390075Sobrien	(ge:SI (match_dup 1) (const_int 0)))]
6854132718Skan  "TARGET_ARM"
685590075Sobrien  "operands[1] = arm_gen_compare_reg (GE, arm_compare_op0, arm_compare_op1);"
685690075Sobrien)
685790075Sobrien
685890075Sobrien(define_expand "slt"
685990075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
686090075Sobrien	(lt:SI (match_dup 1) (const_int 0)))]
6861132718Skan  "TARGET_ARM"
686290075Sobrien  "operands[1] = arm_gen_compare_reg (LT, arm_compare_op0, arm_compare_op1);"
686390075Sobrien)
686490075Sobrien
686590075Sobrien(define_expand "sgtu"
686690075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
686790075Sobrien	(gtu:SI (match_dup 1) (const_int 0)))]
6868132718Skan  "TARGET_ARM"
686990075Sobrien  "operands[1] = arm_gen_compare_reg (GTU, arm_compare_op0, arm_compare_op1);"
687090075Sobrien)
687190075Sobrien
687290075Sobrien(define_expand "sleu"
687390075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
687490075Sobrien	(leu:SI (match_dup 1) (const_int 0)))]
6875132718Skan  "TARGET_ARM"
687690075Sobrien  "operands[1] = arm_gen_compare_reg (LEU, arm_compare_op0, arm_compare_op1);"
687790075Sobrien)
687890075Sobrien
687990075Sobrien(define_expand "sgeu"
688090075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
688190075Sobrien	(geu:SI (match_dup 1) (const_int 0)))]
6882132718Skan  "TARGET_ARM"
688390075Sobrien  "operands[1] = arm_gen_compare_reg (GEU, arm_compare_op0, arm_compare_op1);"
688490075Sobrien)
688590075Sobrien
688690075Sobrien(define_expand "sltu"
688790075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
688890075Sobrien	(ltu:SI (match_dup 1) (const_int 0)))]
6889132718Skan  "TARGET_ARM"
689090075Sobrien  "operands[1] = arm_gen_compare_reg (LTU, arm_compare_op0, arm_compare_op1);"
689190075Sobrien)
689290075Sobrien
689390075Sobrien(define_expand "sunordered"
689490075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
689590075Sobrien	(unordered:SI (match_dup 1) (const_int 0)))]
6896132718Skan  "TARGET_ARM && TARGET_HARD_FLOAT"
689790075Sobrien  "operands[1] = arm_gen_compare_reg (UNORDERED, arm_compare_op0,
689890075Sobrien				      arm_compare_op1);"
689990075Sobrien)
690090075Sobrien
690190075Sobrien(define_expand "sordered"
690290075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
690390075Sobrien	(ordered:SI (match_dup 1) (const_int 0)))]
6904132718Skan  "TARGET_ARM && TARGET_HARD_FLOAT"
690590075Sobrien  "operands[1] = arm_gen_compare_reg (ORDERED, arm_compare_op0,
690690075Sobrien				      arm_compare_op1);"
690790075Sobrien)
690890075Sobrien
690990075Sobrien(define_expand "sungt"
691090075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
691190075Sobrien	(ungt:SI (match_dup 1) (const_int 0)))]
6912132718Skan  "TARGET_ARM && TARGET_HARD_FLOAT"
691390075Sobrien  "operands[1] = arm_gen_compare_reg (UNGT, arm_compare_op0,
691490075Sobrien				      arm_compare_op1);"
691590075Sobrien)
691690075Sobrien
691790075Sobrien(define_expand "sunge"
691890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
691990075Sobrien	(unge:SI (match_dup 1) (const_int 0)))]
6920132718Skan  "TARGET_ARM && TARGET_HARD_FLOAT"
692190075Sobrien  "operands[1] = arm_gen_compare_reg (UNGE, arm_compare_op0,
692290075Sobrien				      arm_compare_op1);"
692390075Sobrien)
692490075Sobrien
692590075Sobrien(define_expand "sunlt"
692690075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
692790075Sobrien	(unlt:SI (match_dup 1) (const_int 0)))]
6928132718Skan  "TARGET_ARM && TARGET_HARD_FLOAT"
692990075Sobrien  "operands[1] = arm_gen_compare_reg (UNLT, arm_compare_op0,
693090075Sobrien				      arm_compare_op1);"
693190075Sobrien)
693290075Sobrien
693390075Sobrien(define_expand "sunle"
693490075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
693590075Sobrien	(unle:SI (match_dup 1) (const_int 0)))]
6936132718Skan  "TARGET_ARM && TARGET_HARD_FLOAT"
693790075Sobrien  "operands[1] = arm_gen_compare_reg (UNLE, arm_compare_op0,
693890075Sobrien				      arm_compare_op1);"
693990075Sobrien)
694090075Sobrien
694190075Sobrien;;; DO NOT add patterns for SUNEQ or SLTGT, these can't be represented with
694290075Sobrien;;; simple ARM instructions. 
694390075Sobrien;
694490075Sobrien; (define_expand "suneq"
694590075Sobrien;   [(set (match_operand:SI 0 "s_register_operand" "")
694690075Sobrien; 	(uneq:SI (match_dup 1) (const_int 0)))]
6947132718Skan;   "TARGET_ARM && TARGET_HARD_FLOAT"
694890075Sobrien;   "abort ();"
694990075Sobrien; )
695090075Sobrien;
695190075Sobrien; (define_expand "sltgt"
695290075Sobrien;   [(set (match_operand:SI 0 "s_register_operand" "")
695390075Sobrien; 	(ltgt:SI (match_dup 1) (const_int 0)))]
6954132718Skan;   "TARGET_ARM && TARGET_HARD_FLOAT"
695590075Sobrien;   "abort ();"
695690075Sobrien; )
695790075Sobrien
695890075Sobrien(define_insn "*mov_scc"
695990075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
696090075Sobrien	(match_operator:SI 1 "arm_comparison_operator"
696190075Sobrien	 [(match_operand 2 "cc_register" "") (const_int 0)]))]
696290075Sobrien  "TARGET_ARM"
696390075Sobrien  "mov%D1\\t%0, #0\;mov%d1\\t%0, #1"
696490075Sobrien  [(set_attr "conds" "use")
696590075Sobrien   (set_attr "length" "8")]
696690075Sobrien)
696790075Sobrien
696890075Sobrien(define_insn "*mov_negscc"
696990075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
697090075Sobrien	(neg:SI (match_operator:SI 1 "arm_comparison_operator"
697190075Sobrien		 [(match_operand 2 "cc_register" "") (const_int 0)])))]
697290075Sobrien  "TARGET_ARM"
697390075Sobrien  "mov%D1\\t%0, #0\;mvn%d1\\t%0, #0"
697490075Sobrien  [(set_attr "conds" "use")
697590075Sobrien   (set_attr "length" "8")]
697690075Sobrien)
697790075Sobrien
697890075Sobrien(define_insn "*mov_notscc"
697990075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
698090075Sobrien	(not:SI (match_operator:SI 1 "arm_comparison_operator"
698190075Sobrien		 [(match_operand 2 "cc_register" "") (const_int 0)])))]
698290075Sobrien  "TARGET_ARM"
698390075Sobrien  "mov%D1\\t%0, #0\;mvn%d1\\t%0, #1"
698490075Sobrien  [(set_attr "conds" "use")
698590075Sobrien   (set_attr "length" "8")]
698690075Sobrien)
698790075Sobrien
698890075Sobrien
698990075Sobrien;; Conditional move insns
699090075Sobrien
699190075Sobrien(define_expand "movsicc"
699290075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
699390075Sobrien	(if_then_else:SI (match_operand 1 "arm_comparison_operator" "")
699490075Sobrien			 (match_operand:SI 2 "arm_not_operand" "")
699590075Sobrien			 (match_operand:SI 3 "arm_not_operand" "")))]
699690075Sobrien  "TARGET_ARM"
699790075Sobrien  "
699890075Sobrien  {
699990075Sobrien    enum rtx_code code = GET_CODE (operands[1]);
700090075Sobrien    rtx ccreg;
700190075Sobrien
7002117395Skan    if (code == UNEQ || code == LTGT)
700390075Sobrien      FAIL;
7004117395Skan
7005117395Skan    ccreg = arm_gen_compare_reg (code, arm_compare_op0, arm_compare_op1);
7006117395Skan    operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx);
7007117395Skan  }"
700890075Sobrien)
700990075Sobrien
701090075Sobrien(define_expand "movsfcc"
701190075Sobrien  [(set (match_operand:SF 0 "s_register_operand" "")
701290075Sobrien	(if_then_else:SF (match_operand 1 "arm_comparison_operator" "")
701390075Sobrien			 (match_operand:SF 2 "s_register_operand" "")
701490075Sobrien			 (match_operand:SF 3 "nonmemory_operand" "")))]
701590075Sobrien  "TARGET_ARM"
701690075Sobrien  "
701790075Sobrien  {
701890075Sobrien    enum rtx_code code = GET_CODE (operands[1]);
701990075Sobrien    rtx ccreg;
702090075Sobrien
702190075Sobrien    if (code == UNEQ || code == LTGT)
702290075Sobrien      FAIL;
7023117395Skan
7024117395Skan    /* When compiling for SOFT_FLOAT, ensure both arms are in registers. 
7025117395Skan       Otherwise, ensure it is a valid FP add operand.  */
702690075Sobrien    if ((!TARGET_HARD_FLOAT)
7027132718Skan        || (!fpa_add_operand (operands[3], SFmode)))
702890075Sobrien      operands[3] = force_reg (SFmode, operands[3]);
7029132718Skan
703090075Sobrien    ccreg = arm_gen_compare_reg (code, arm_compare_op0, arm_compare_op1);
703190075Sobrien    operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx);
703290075Sobrien  }"
703390075Sobrien)
703490075Sobrien
703590075Sobrien(define_expand "movdfcc"
703690075Sobrien  [(set (match_operand:DF 0 "s_register_operand" "")
703790075Sobrien	(if_then_else:DF (match_operand 1 "arm_comparison_operator" "")
703890075Sobrien			 (match_operand:DF 2 "s_register_operand" "")
703990075Sobrien			 (match_operand:DF 3 "fpa_add_operand" "")))]
704090075Sobrien  "TARGET_ARM && TARGET_HARD_FLOAT"
7041132718Skan  "
704290075Sobrien  {
704390075Sobrien    enum rtx_code code = GET_CODE (operands[1]);
704490075Sobrien    rtx ccreg;
704590075Sobrien
7046117395Skan    if (code == UNEQ || code == LTGT)
704790075Sobrien      FAIL;
7048117395Skan
7049117395Skan    ccreg = arm_gen_compare_reg (code, arm_compare_op0, arm_compare_op1);
7050117395Skan    operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx);
7051117395Skan  }"
705290075Sobrien)
705390075Sobrien
705490075Sobrien(define_insn "*movsicc_insn"
705590075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r,r,r,r,r")
705690075Sobrien	(if_then_else:SI
705790075Sobrien	 (match_operator 3 "arm_comparison_operator"
705890075Sobrien	  [(match_operand 4 "cc_register" "") (const_int 0)])
705990075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,0,rI,K,rI,rI,K,K")
706090075Sobrien	 (match_operand:SI 2 "arm_not_operand" "rI,K,0,0,rI,K,rI,K")))]
706190075Sobrien  "TARGET_ARM"
706290075Sobrien  "@
706390075Sobrien   mov%D3\\t%0, %2
706490075Sobrien   mvn%D3\\t%0, #%B2
706590075Sobrien   mov%d3\\t%0, %1
706690075Sobrien   mvn%d3\\t%0, #%B1
706790075Sobrien   mov%d3\\t%0, %1\;mov%D3\\t%0, %2
706890075Sobrien   mov%d3\\t%0, %1\;mvn%D3\\t%0, #%B2
706990075Sobrien   mvn%d3\\t%0, #%B1\;mov%D3\\t%0, %2
707090075Sobrien   mvn%d3\\t%0, #%B1\;mvn%D3\\t%0, #%B2"
707190075Sobrien  [(set_attr "length" "4,4,4,4,8,8,8,8")
707290075Sobrien   (set_attr "conds" "use")]
707390075Sobrien)
707490075Sobrien
707590075Sobrien(define_insn "*movsfcc_soft_insn"
707690075Sobrien  [(set (match_operand:SF 0 "s_register_operand" "=r,r")
707790075Sobrien	(if_then_else:SF (match_operator 3 "arm_comparison_operator"
707890075Sobrien			  [(match_operand 4 "cc_register" "") (const_int 0)])
707990075Sobrien			 (match_operand:SF 1 "s_register_operand" "0,r")
708090075Sobrien			 (match_operand:SF 2 "s_register_operand" "r,0")))]
708190075Sobrien  "TARGET_ARM && TARGET_SOFT_FLOAT"
708290075Sobrien  "@
708390075Sobrien   mov%D3\\t%0, %2
708490075Sobrien   mov%d3\\t%0, %1"
708590075Sobrien  [(set_attr "conds" "use")]
708690075Sobrien)
708790075Sobrien
708890075Sobrien
708990075Sobrien;; Jump and linkage insns
709090075Sobrien
709190075Sobrien(define_expand "jump"
709290075Sobrien  [(set (pc)
709390075Sobrien	(label_ref (match_operand 0 "" "")))]
709490075Sobrien  "TARGET_EITHER"
709590075Sobrien  ""
709690075Sobrien)
709790075Sobrien
709890075Sobrien(define_insn "*arm_jump"
709990075Sobrien  [(set (pc)
710090075Sobrien	(label_ref (match_operand 0 "" "")))]
710190075Sobrien  "TARGET_ARM"
710290075Sobrien  "*
710390075Sobrien  {
710490075Sobrien    if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2)
710590075Sobrien      {
710690075Sobrien        arm_ccfsm_state += 2;
710790075Sobrien        return \"\";
710890075Sobrien      }
710990075Sobrien    return \"b%?\\t%l0\";
711090075Sobrien  }
711190075Sobrien  "
711290075Sobrien  [(set_attr "predicable" "yes")]
711390075Sobrien)
711490075Sobrien
711590075Sobrien(define_insn "*thumb_jump"
711690075Sobrien  [(set (pc)
711790075Sobrien	(label_ref (match_operand 0 "" "")))]
711890075Sobrien  "TARGET_THUMB"
711990075Sobrien  "*
712090075Sobrien  if (get_attr_length (insn) == 2)
712190075Sobrien    return \"b\\t%l0\";
712290075Sobrien  return \"bl\\t%l0\\t%@ far jump\";
712390075Sobrien  "
712490075Sobrien  [(set (attr "far_jump")
712590075Sobrien        (if_then_else
712690075Sobrien	    (eq_attr "length" "4")
712790075Sobrien	    (const_string "yes")
712890075Sobrien	    (const_string "no")))
712990075Sobrien   (set (attr "length") 
713090075Sobrien        (if_then_else
713190075Sobrien	    (and (ge (minus (match_dup 0) (pc)) (const_int -2048))
713290075Sobrien		 (le (minus (match_dup 0) (pc)) (const_int 2044)))
7133146895Skan  	    (const_int 2)
7134146895Skan	    (const_int 4)))]
713590075Sobrien)
713690075Sobrien
713790075Sobrien(define_expand "call"
713890075Sobrien  [(parallel [(call (match_operand 0 "memory_operand" "")
713990075Sobrien	            (match_operand 1 "general_operand" ""))
714090075Sobrien	      (use (match_operand 2 "" ""))
714190075Sobrien	      (clobber (reg:SI LR_REGNUM))])]
714290075Sobrien  "TARGET_EITHER"
714390075Sobrien  "
714490075Sobrien  {
714590075Sobrien    rtx callee;
714690075Sobrien    
714790075Sobrien    /* In an untyped call, we can get NULL for operand 2.  */
714890075Sobrien    if (operands[2] == NULL_RTX)
714990075Sobrien      operands[2] = const0_rtx;
715090075Sobrien      
715190075Sobrien    /* This is to decide if we should generate indirect calls by loading the
715290075Sobrien       32 bit address of the callee into a register before performing the
715390075Sobrien       branch and link.  operand[2] encodes the long_call/short_call
715490075Sobrien       attribute of the function being called.  This attribute is set whenever
715590075Sobrien       __attribute__((long_call/short_call)) or #pragma long_call/no_long_call
715690075Sobrien       is used, and the short_call attribute can also be set if function is
715790075Sobrien       declared as static or if it has already been defined in the current
715890075Sobrien       compilation unit.  See arm.c and arm.h for info about this.  The third
715990075Sobrien       parameter to arm_is_longcall_p is used to tell it which pattern
716090075Sobrien       invoked it.  */
716190075Sobrien    callee  = XEXP (operands[0], 0);
716290075Sobrien    
716390075Sobrien    if (GET_CODE (callee) != REG
716490075Sobrien       && arm_is_longcall_p (operands[0], INTVAL (operands[2]), 0))
716590075Sobrien      XEXP (operands[0], 0) = force_reg (Pmode, callee);
716690075Sobrien  }"
716790075Sobrien)
716890075Sobrien
716990075Sobrien(define_insn "*call_reg"
717090075Sobrien  [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r"))
717190075Sobrien         (match_operand 1 "" ""))
717290075Sobrien   (use (match_operand 2 "" ""))
717390075Sobrien   (clobber (reg:SI LR_REGNUM))]
717490075Sobrien  "TARGET_ARM"
717590075Sobrien  "*
717690075Sobrien  return output_call (operands);
717790075Sobrien  "
717890075Sobrien  ;; length is worst case, normally it is only two
717990075Sobrien  [(set_attr "length" "12")
718090075Sobrien   (set_attr "type" "call")]
718190075Sobrien)
718290075Sobrien
718390075Sobrien(define_insn "*call_mem"
718490075Sobrien  [(call (mem:SI (match_operand:SI 0 "memory_operand" "m"))
718590075Sobrien	 (match_operand 1 "" ""))
718690075Sobrien   (use (match_operand 2 "" ""))
718790075Sobrien   (clobber (reg:SI LR_REGNUM))]
718890075Sobrien  "TARGET_ARM"
718990075Sobrien  "*
719090075Sobrien  return output_call_mem (operands);
719190075Sobrien  "
719290075Sobrien  [(set_attr "length" "12")
719390075Sobrien   (set_attr "type" "call")]
719490075Sobrien)
719590075Sobrien
719690075Sobrien(define_insn "*call_indirect"
719790075Sobrien  [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
719890075Sobrien	 (match_operand 1 "" ""))
719990075Sobrien   (use (match_operand 2 "" ""))
720090075Sobrien   (clobber (reg:SI LR_REGNUM))]
720190075Sobrien  "TARGET_THUMB"
720290075Sobrien  "*
720390075Sobrien  {
720490075Sobrien    if (TARGET_CALLER_INTERWORKING)
720590075Sobrien      return \"bl\\t%__interwork_call_via_%0\";
720690075Sobrien    else
720790075Sobrien      return \"bl\\t%__call_via_%0\";
720890075Sobrien  }"
720990075Sobrien  [(set_attr "type" "call")]
721090075Sobrien)
721190075Sobrien
721290075Sobrien(define_insn "*call_value_indirect"
721390075Sobrien  [(set (match_operand 0 "" "")
721490075Sobrien	(call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
7215132718Skan	      (match_operand 2 "" "")))
721690075Sobrien   (use (match_operand 3 "" ""))
721790075Sobrien   (clobber (reg:SI LR_REGNUM))]
721890075Sobrien  "TARGET_THUMB"
721990075Sobrien  "*
722090075Sobrien  {
722190075Sobrien    if (TARGET_CALLER_INTERWORKING)
722290075Sobrien      return \"bl\\t%__interwork_call_via_%1\";
722390075Sobrien    else
722490075Sobrien      return \"bl\\t%__call_via_%1\";
722590075Sobrien  }"
722690075Sobrien  [(set_attr "type" "call")]
722790075Sobrien)
722890075Sobrien
722990075Sobrien(define_expand "call_value"
723090075Sobrien  [(parallel [(set (match_operand       0 "" "")
723190075Sobrien	           (call (match_operand 1 "memory_operand" "")
723290075Sobrien		         (match_operand 2 "general_operand" "")))
723390075Sobrien	      (use (match_operand 3 "" ""))
723490075Sobrien	      (clobber (reg:SI LR_REGNUM))])]
723590075Sobrien  "TARGET_EITHER"
723690075Sobrien  "
723790075Sobrien  {
723890075Sobrien    rtx callee = XEXP (operands[1], 0);
723990075Sobrien    
724090075Sobrien    /* In an untyped call, we can get NULL for operand 2.  */
724190075Sobrien    if (operands[3] == 0)
724290075Sobrien      operands[3] = const0_rtx;
724390075Sobrien      
724490075Sobrien    /* See the comment in define_expand \"call\".  */
724590075Sobrien    if (GET_CODE (callee) != REG
724690075Sobrien	&& arm_is_longcall_p (operands[1], INTVAL (operands[3]), 0))
724790075Sobrien      XEXP (operands[1], 0) = force_reg (Pmode, callee);
724890075Sobrien  }"
724990075Sobrien)
725090075Sobrien
725190075Sobrien(define_insn "*call_value_reg"
725290075Sobrien  [(set (match_operand 0 "" "")
725390075Sobrien        (call (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
7254132718Skan	      (match_operand 2 "" "")))
7255132718Skan   (use (match_operand 3 "" ""))
725690075Sobrien   (clobber (reg:SI LR_REGNUM))]
725790075Sobrien  "TARGET_ARM"
725890075Sobrien  "*
725990075Sobrien  return output_call (&operands[1]);
726090075Sobrien  "
726190075Sobrien  [(set_attr "length" "12")
726290075Sobrien   (set_attr "type" "call")]
726390075Sobrien)
726490075Sobrien
726590075Sobrien(define_insn "*call_value_mem"
726690075Sobrien  [(set (match_operand 0 "" "")
726790075Sobrien	(call (mem:SI (match_operand:SI 1 "memory_operand" "m"))
7268132718Skan	      (match_operand 2 "" "")))
7269132718Skan   (use (match_operand 3 "" ""))
727090075Sobrien   (clobber (reg:SI LR_REGNUM))]
727190075Sobrien  "TARGET_ARM && (!CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))"
727290075Sobrien  "*
727390075Sobrien  return output_call_mem (&operands[1]);
727490075Sobrien  "
727590075Sobrien  [(set_attr "length" "12")
727690075Sobrien   (set_attr "type" "call")]
727790075Sobrien)
727890075Sobrien
727990075Sobrien;; Allow calls to SYMBOL_REFs specially as they are not valid general addresses
728090075Sobrien;; The 'a' causes the operand to be treated as an address, i.e. no '#' output.
728190075Sobrien
728290075Sobrien(define_insn "*call_symbol"
728390075Sobrien  [(call (mem:SI (match_operand:SI 0 "" ""))
728490075Sobrien	 (match_operand 1 "" ""))
7285132718Skan   (use (match_operand 2 "" ""))
728690075Sobrien   (clobber (reg:SI LR_REGNUM))]
728790075Sobrien  "TARGET_ARM
728890075Sobrien   && (GET_CODE (operands[0]) == SYMBOL_REF)
728990075Sobrien   && !arm_is_longcall_p (operands[0], INTVAL (operands[2]), 1)"
729090075Sobrien  "*
729190075Sobrien  {
729290075Sobrien    return NEED_PLT_RELOC ? \"bl%?\\t%a0(PLT)\" : \"bl%?\\t%a0\";
729390075Sobrien  }"
729490075Sobrien  [(set_attr "type" "call")]
729590075Sobrien)
729690075Sobrien
729790075Sobrien(define_insn "*call_value_symbol"
729890075Sobrien  [(set (match_operand 0 "s_register_operand" "")
729990075Sobrien	(call (mem:SI (match_operand:SI 1 "" ""))
7300132718Skan	(match_operand:SI 2 "" "")))
7301132718Skan   (use (match_operand 3 "" ""))
730290075Sobrien   (clobber (reg:SI LR_REGNUM))]
730390075Sobrien  "TARGET_ARM
730490075Sobrien   && (GET_CODE (operands[1]) == SYMBOL_REF)
730590075Sobrien   && !arm_is_longcall_p (operands[1], INTVAL (operands[3]), 1)"
730690075Sobrien  "*
730790075Sobrien  {
730890075Sobrien    return NEED_PLT_RELOC ? \"bl%?\\t%a1(PLT)\" : \"bl%?\\t%a1\";
730990075Sobrien  }"
731090075Sobrien  [(set_attr "type" "call")]
731190075Sobrien)
731290075Sobrien
731390075Sobrien(define_insn "*call_insn"
731490075Sobrien  [(call (mem:SI (match_operand:SI 0 "" ""))
731590075Sobrien	 (match_operand:SI 1 "" ""))
7316132718Skan   (use (match_operand 2 "" ""))
731790075Sobrien   (clobber (reg:SI LR_REGNUM))]
731890075Sobrien  "TARGET_THUMB
731990075Sobrien   && GET_CODE (operands[0]) == SYMBOL_REF
732090075Sobrien   && !arm_is_longcall_p (operands[0], INTVAL (operands[2]), 1)"
732196263Sobrien  "bl\\t%a0"
732296263Sobrien  [(set_attr "length" "4")
732390075Sobrien   (set_attr "type" "call")]
732490075Sobrien)
732590075Sobrien
732690075Sobrien(define_insn "*call_value_insn"
732790075Sobrien  [(set (match_operand 0 "register_operand" "")
732890075Sobrien	(call (mem:SI (match_operand 1 "" ""))
7329132718Skan	      (match_operand 2 "" "")))
7330132718Skan   (use (match_operand 3 "" ""))
733190075Sobrien   (clobber (reg:SI LR_REGNUM))]
733290075Sobrien  "TARGET_THUMB
733390075Sobrien   && GET_CODE (operands[1]) == SYMBOL_REF
733490075Sobrien   && !arm_is_longcall_p (operands[1], INTVAL (operands[3]), 1)"
733596263Sobrien  "bl\\t%a1"
733696263Sobrien  [(set_attr "length" "4")
733790075Sobrien   (set_attr "type" "call")]
733890075Sobrien)
733990075Sobrien
734090075Sobrien;; We may also be able to do sibcalls for Thumb, but it's much harder...
734190075Sobrien(define_expand "sibcall"
734290075Sobrien  [(parallel [(call (match_operand 0 "memory_operand" "")
734390075Sobrien		    (match_operand 1 "general_operand" ""))
734490075Sobrien	      (return)
734590075Sobrien	      (use (match_operand 2 "" ""))])]
7346117395Skan  "TARGET_ARM"
7347117395Skan  "
734890075Sobrien  {
734990075Sobrien    if (operands[2] == NULL_RTX)
735090075Sobrien      operands[2] = const0_rtx;
735190075Sobrien  }"
735290075Sobrien)
735390075Sobrien
735490075Sobrien(define_expand "sibcall_value"
735590075Sobrien  [(parallel [(set (match_operand 0 "register_operand" "")
735690075Sobrien		   (call (match_operand 1 "memory_operand" "")
735790075Sobrien			 (match_operand 2 "general_operand" "")))
735890075Sobrien	      (return)
735990075Sobrien	      (use (match_operand 3 "" ""))])]
7360117395Skan  "TARGET_ARM"
7361117395Skan  "
736290075Sobrien  {
736390075Sobrien    if (operands[3] == NULL_RTX)
736490075Sobrien      operands[3] = const0_rtx;
736590075Sobrien  }"
736690075Sobrien)
736790075Sobrien
736890075Sobrien(define_insn "*sibcall_insn"
736990075Sobrien [(call (mem:SI (match_operand:SI 0 "" "X"))
737090075Sobrien	(match_operand 1 "" ""))
737190075Sobrien  (return)
737290075Sobrien  (use (match_operand 2 "" ""))]
7373117395Skan  "TARGET_ARM && GET_CODE (operands[0]) == SYMBOL_REF"
7374117395Skan  "*
737590075Sobrien  return NEED_PLT_RELOC ? \"b%?\\t%a0(PLT)\" : \"b%?\\t%a0\";
737690075Sobrien  "
737790075Sobrien  [(set_attr "type" "call")]
737890075Sobrien)
737990075Sobrien
738090075Sobrien(define_insn "*sibcall_value_insn"
738190075Sobrien [(set (match_operand 0 "s_register_operand" "")
738290075Sobrien       (call (mem:SI (match_operand:SI 1 "" "X"))
7383132718Skan	     (match_operand 2 "" "")))
7384132718Skan  (return)
738590075Sobrien  (use (match_operand 3 "" ""))]
7386117395Skan  "TARGET_ARM && GET_CODE (operands[1]) == SYMBOL_REF"
7387117395Skan  "*
738890075Sobrien  return NEED_PLT_RELOC ? \"b%?\\t%a1(PLT)\" : \"b%?\\t%a1\";
738990075Sobrien  "
739090075Sobrien  [(set_attr "type" "call")]
739190075Sobrien)
739290075Sobrien
739390075Sobrien;; Often the return insn will be the same as loading from memory, so set attr
739490075Sobrien(define_insn "return"
739590075Sobrien  [(return)]
739690075Sobrien  "TARGET_ARM && USE_RETURN_INSN (FALSE)"
739790075Sobrien  "*
739890075Sobrien  {
739990075Sobrien    if (arm_ccfsm_state == 2)
740090075Sobrien      {
740190075Sobrien        arm_ccfsm_state += 2;
740290075Sobrien        return \"\";
740390075Sobrien      }
740490075Sobrien    return output_return_instruction (const_true_rtx, TRUE, FALSE);
740590075Sobrien  }"
7406117395Skan  [(set_attr "type" "load")
740790075Sobrien   (set_attr "length" "12")
740890075Sobrien   (set_attr "predicable" "yes")]
7409132718Skan)
741090075Sobrien
741190075Sobrien(define_insn "*cond_return"
741290075Sobrien  [(set (pc)
741390075Sobrien        (if_then_else (match_operator 0 "arm_comparison_operator"
741490075Sobrien		       [(match_operand 1 "cc_register" "") (const_int 0)])
741590075Sobrien                      (return)
741690075Sobrien                      (pc)))]
741790075Sobrien  "TARGET_ARM && USE_RETURN_INSN (TRUE)"
741890075Sobrien  "*
741990075Sobrien  {
742090075Sobrien    if (arm_ccfsm_state == 2)
742190075Sobrien      {
742290075Sobrien        arm_ccfsm_state += 2;
742390075Sobrien        return \"\";
742490075Sobrien      }
742590075Sobrien    return output_return_instruction (operands[0], TRUE, FALSE);
742690075Sobrien  }"
742790075Sobrien  [(set_attr "conds" "use")
742890075Sobrien   (set_attr "length" "12")
742990075Sobrien   (set_attr "type" "load")]
7430132718Skan)
743190075Sobrien
743290075Sobrien(define_insn "*cond_return_inverted"
743390075Sobrien  [(set (pc)
743490075Sobrien        (if_then_else (match_operator 0 "arm_comparison_operator"
743590075Sobrien		       [(match_operand 1 "cc_register" "") (const_int 0)])
743690075Sobrien                      (pc)
743790075Sobrien		      (return)))]
743890075Sobrien  "TARGET_ARM && USE_RETURN_INSN (TRUE)"
743990075Sobrien  "*
744090075Sobrien  {
744190075Sobrien    if (arm_ccfsm_state == 2)
744290075Sobrien      {
744390075Sobrien        arm_ccfsm_state += 2;
744490075Sobrien        return \"\";
744590075Sobrien      }
744690075Sobrien    return output_return_instruction (operands[0], TRUE, TRUE);
744790075Sobrien  }"
744890075Sobrien  [(set_attr "conds" "use")
744990075Sobrien   (set_attr "type" "load")]
745090075Sobrien)
745190075Sobrien
745290075Sobrien;; Generate a sequence of instructions to determine if the processor is
745390075Sobrien;; in 26-bit or 32-bit mode, and return the appropriate return address
7454117395Skan;; mask.
7455117395Skan
7456117395Skan(define_expand "return_addr_mask"
7457117395Skan  [(set (match_dup 1)
7458117395Skan      (compare:CC_NOOV (unspec [(const_int 0)] UNSPEC_CHECK_ARCH)
7459117395Skan		       (const_int 0)))
7460117395Skan   (set (match_operand:SI 0 "s_register_operand" "")
7461117395Skan      (if_then_else:SI (eq (match_dup 1) (const_int 0))
7462117395Skan		       (const_int -1)
7463117395Skan		       (const_int 67108860)))] ; 0x03fffffc
7464117395Skan  "TARGET_ARM"
7465117395Skan  "
7466117395Skan  operands[1] = gen_rtx_REG (CC_NOOVmode, CC_REGNUM);
7467117395Skan  ")
7468132718Skan
7469117395Skan(define_insn "*check_arch2"
7470117395Skan  [(set (match_operand:CC_NOOV 0 "cc_register" "")
7471117395Skan      (compare:CC_NOOV (unspec [(const_int 0)] UNSPEC_CHECK_ARCH)
7472117395Skan		       (const_int 0)))]
7473117395Skan  "TARGET_ARM"
7474117395Skan  "teq\\t%|r0, %|r0\;teq\\t%|pc, %|pc"
7475117395Skan  [(set_attr "length" "8")
7476117395Skan   (set_attr "conds" "set")]
7477117395Skan)
7478117395Skan
7479117395Skan;; Call subroutine returning any type.
7480117395Skan
748190075Sobrien(define_expand "untyped_call"
748290075Sobrien  [(parallel [(call (match_operand 0 "" "")
748390075Sobrien		    (const_int 0))
748490075Sobrien	      (match_operand 1 "" "")
748590075Sobrien	      (match_operand 2 "" "")])]
748690075Sobrien  "TARGET_ARM"
748790075Sobrien  "
748890075Sobrien  {
748990075Sobrien    int i;
749090075Sobrien
749190075Sobrien    emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, const0_rtx));
749290075Sobrien
749390075Sobrien    for (i = 0; i < XVECLEN (operands[2], 0); i++)
749490075Sobrien      {
749590075Sobrien	rtx set = XVECEXP (operands[2], 0, i);
749690075Sobrien
749790075Sobrien	emit_move_insn (SET_DEST (set), SET_SRC (set));
749890075Sobrien      }
749990075Sobrien
750090075Sobrien    /* The optimizer does not know that the call sets the function value
750190075Sobrien       registers we stored in the result block.  We avoid problems by
750290075Sobrien       claiming that all hard registers are used and clobbered at this
750390075Sobrien       point.  */
750490075Sobrien    emit_insn (gen_blockage ());
750590075Sobrien
750690075Sobrien    DONE;
750790075Sobrien  }"
750890075Sobrien)
750990075Sobrien
751090075Sobrien;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
751190075Sobrien;; all of memory.  This blocks insns from being moved across this point.
751290075Sobrien
751390075Sobrien(define_insn "blockage"
751490075Sobrien  [(unspec_volatile [(const_int 0)] VUNSPEC_BLOCKAGE)]
751590075Sobrien  "TARGET_EITHER"
751690075Sobrien  ""
751790075Sobrien  [(set_attr "length" "0")
751890075Sobrien   (set_attr "type" "block")]
751990075Sobrien)
752090075Sobrien
752190075Sobrien(define_expand "casesi"
752290075Sobrien  [(match_operand:SI 0 "s_register_operand" "")	; index to jump on
752390075Sobrien   (match_operand:SI 1 "const_int_operand" "")	; lower bound
752490075Sobrien   (match_operand:SI 2 "const_int_operand" "")	; total range
752590075Sobrien   (match_operand:SI 3 "" "")			; table label
752690075Sobrien   (match_operand:SI 4 "" "")]			; Out of range label
752790075Sobrien  "TARGET_ARM"
752890075Sobrien  "
752990075Sobrien  {
753090075Sobrien    rtx reg;
753190075Sobrien    if (operands[1] != const0_rtx)
753290075Sobrien      {
753390075Sobrien	reg = gen_reg_rtx (SImode);
753490075Sobrien
753590075Sobrien	emit_insn (gen_addsi3 (reg, operands[0],
753690075Sobrien			       GEN_INT (-INTVAL (operands[1]))));
753790075Sobrien	operands[0] = reg;
753890075Sobrien      }
753990075Sobrien
754090075Sobrien    if (!const_ok_for_arm (INTVAL (operands[2])))
754190075Sobrien      operands[2] = force_reg (SImode, operands[2]);
754290075Sobrien
754390075Sobrien    emit_jump_insn (gen_casesi_internal (operands[0], operands[2], operands[3],
754490075Sobrien					 operands[4]));
754590075Sobrien    DONE;
754690075Sobrien  }"
754790075Sobrien)
754890075Sobrien
754990075Sobrien;; The USE in this pattern is needed to tell flow analysis that this is
755090075Sobrien;; a CASESI insn.  It has no other purpose.
755190075Sobrien(define_insn "casesi_internal"
755290075Sobrien  [(parallel [(set (pc)
755390075Sobrien	       (if_then_else
755490075Sobrien		(leu (match_operand:SI 0 "s_register_operand" "r")
755590075Sobrien		     (match_operand:SI 1 "arm_rhs_operand" "rI"))
755690075Sobrien		(mem:SI (plus:SI (mult:SI (match_dup 0) (const_int 4))
755790075Sobrien				 (label_ref (match_operand 2 "" ""))))
755890075Sobrien		(label_ref (match_operand 3 "" ""))))
755990075Sobrien	      (clobber (reg:CC CC_REGNUM))
756090075Sobrien	      (use (label_ref (match_dup 2)))])]
756190075Sobrien  "TARGET_ARM"
756290075Sobrien  "*
756390075Sobrien    if (flag_pic)
756490075Sobrien      return \"cmp\\t%0, %1\;addls\\t%|pc, %|pc, %0, asl #2\;b\\t%l3\";
756590075Sobrien    return   \"cmp\\t%0, %1\;ldrls\\t%|pc, [%|pc, %0, asl #2]\;b\\t%l3\";
756690075Sobrien  "
756790075Sobrien  [(set_attr "conds" "clob")
756890075Sobrien   (set_attr "length" "12")]
756990075Sobrien)
757090075Sobrien
757190075Sobrien(define_expand "indirect_jump"
757290075Sobrien  [(set (pc)
757390075Sobrien	(match_operand:SI 0 "s_register_operand" ""))]
757490075Sobrien  "TARGET_EITHER"
757590075Sobrien  ""
757690075Sobrien)
757790075Sobrien
757890075Sobrien(define_insn "*arm_indirect_jump"
757990075Sobrien  [(set (pc)
758090075Sobrien	(match_operand:SI 0 "s_register_operand" "r"))]
758190075Sobrien  "TARGET_ARM"
758290075Sobrien  "mov%?\\t%|pc, %0\\t%@ indirect register jump"
758390075Sobrien  [(set_attr "predicable" "yes")]
758490075Sobrien)
758590075Sobrien
758690075Sobrien;; Although not supported by the define_expand above,
758790075Sobrien;; cse/combine may generate this form.
758890075Sobrien(define_insn "*load_indirect_jump"
758990075Sobrien  [(set (pc)
759090075Sobrien	(match_operand:SI 0 "memory_operand" "m"))]
759190075Sobrien  "TARGET_ARM"
759290075Sobrien  "ldr%?\\t%|pc, %0\\t%@ indirect memory jump"
759390075Sobrien  [(set_attr "type" "load")
759490075Sobrien   (set_attr "pool_range" "4096")
759590075Sobrien   (set_attr "neg_pool_range" "4084")
759690075Sobrien   (set_attr "predicable" "yes")]
759790075Sobrien)
759890075Sobrien
759990075Sobrien(define_insn "*thumb_indirect_jump"
760090075Sobrien  [(set (pc)
760190075Sobrien	(match_operand:SI 0 "register_operand" "l*r"))]
760290075Sobrien  "TARGET_THUMB"
760390075Sobrien  "mov\\tpc, %0"
760490075Sobrien  [(set_attr "conds" "clob")
760590075Sobrien   (set_attr "length" "2")]
760690075Sobrien)
760790075Sobrien
760890075Sobrien
760990075Sobrien;; Misc insns
761090075Sobrien
761190075Sobrien(define_insn "nop"
761290075Sobrien  [(const_int 0)]
761390075Sobrien  "TARGET_EITHER"
761490075Sobrien  "*
761590075Sobrien  if (TARGET_ARM)
761690075Sobrien    return \"mov%?\\t%|r0, %|r0\\t%@ nop\";
761790075Sobrien  return  \"mov\\tr8, r8\";
761890075Sobrien  "
761990075Sobrien  [(set (attr "length")
762090075Sobrien	(if_then_else (eq_attr "is_thumb" "yes")
762190075Sobrien		      (const_int 2)
762290075Sobrien		      (const_int 4)))]
762390075Sobrien)
762490075Sobrien
762590075Sobrien
762690075Sobrien;; Patterns to allow combination of arithmetic, cond code and shifts
762790075Sobrien
762890075Sobrien(define_insn "*arith_shiftsi"
762990075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
763090075Sobrien        (match_operator:SI 1 "shiftable_operator"
763190075Sobrien          [(match_operator:SI 3 "shift_operator"
763290075Sobrien             [(match_operand:SI 4 "s_register_operand" "r")
763390075Sobrien              (match_operand:SI 5 "reg_or_int_operand" "rI")])
763490075Sobrien           (match_operand:SI 2 "s_register_operand" "r")]))]
763590075Sobrien  "TARGET_ARM"
763690075Sobrien  "%i1%?\\t%0, %2, %4%S3"
763790075Sobrien  [(set_attr "predicable" "yes")
763890075Sobrien   (set_attr "shift" "4")
763990075Sobrien   ]
764090075Sobrien)
764190075Sobrien
764290075Sobrien(define_split
764390075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
7644132718Skan	(match_operator:SI 1 "shiftable_operator"
7645132718Skan	 [(match_operator:SI 2 "shiftable_operator"
7646132718Skan	   [(match_operator:SI 3 "shift_operator"
7647132718Skan	     [(match_operand:SI 4 "s_register_operand" "")
7648132718Skan	      (match_operand:SI 5 "reg_or_int_operand" "")])
7649132718Skan	    (match_operand:SI 6 "s_register_operand" "")])
7650132718Skan	  (match_operand:SI 7 "arm_rhs_operand" "")]))
7651132718Skan   (clobber (match_operand:SI 8 "s_register_operand" ""))]
7652132718Skan  "TARGET_ARM"
7653132718Skan  [(set (match_dup 8)
7654132718Skan	(match_op_dup 2 [(match_op_dup 3 [(match_dup 4) (match_dup 5)])
7655132718Skan			 (match_dup 6)]))
7656132718Skan   (set (match_dup 0)
7657132718Skan	(match_op_dup 1 [(match_dup 8) (match_dup 7)]))]
7658132718Skan  "")
7659132718Skan
7660132718Skan(define_insn "*arith_shiftsi_compare0"
7661132718Skan  [(set (reg:CC_NOOV CC_REGNUM)
766290075Sobrien        (compare:CC_NOOV (match_operator:SI 1 "shiftable_operator"
766390075Sobrien		          [(match_operator:SI 3 "shift_operator"
766490075Sobrien		            [(match_operand:SI 4 "s_register_operand" "r")
766590075Sobrien		             (match_operand:SI 5 "reg_or_int_operand" "rI")])
766690075Sobrien		           (match_operand:SI 2 "s_register_operand" "r")])
766790075Sobrien			 (const_int 0)))
766890075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
766990075Sobrien	(match_op_dup 1 [(match_op_dup 3 [(match_dup 4) (match_dup 5)])
767090075Sobrien			 (match_dup 2)]))]
767190075Sobrien  "TARGET_ARM"
767290075Sobrien  "%i1%?s\\t%0, %2, %4%S3"
767390075Sobrien  [(set_attr "conds" "set")
767490075Sobrien   (set_attr "shift" "4")
767590075Sobrien   ]
767690075Sobrien)
767790075Sobrien
767890075Sobrien(define_insn "*arith_shiftsi_compare0_scratch"
767990075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
768090075Sobrien        (compare:CC_NOOV (match_operator:SI 1 "shiftable_operator"
768190075Sobrien		          [(match_operator:SI 3 "shift_operator"
768290075Sobrien		            [(match_operand:SI 4 "s_register_operand" "r")
768390075Sobrien		             (match_operand:SI 5 "reg_or_int_operand" "rI")])
768490075Sobrien		           (match_operand:SI 2 "s_register_operand" "r")])
768590075Sobrien			 (const_int 0)))
768690075Sobrien   (clobber (match_scratch:SI 0 "=r"))]
768790075Sobrien  "TARGET_ARM"
768890075Sobrien  "%i1%?s\\t%0, %2, %4%S3"
768990075Sobrien  [(set_attr "conds" "set")
769090075Sobrien   (set_attr "shift" "4")
769190075Sobrien   ]
769290075Sobrien)
769390075Sobrien
769490075Sobrien(define_insn "*sub_shiftsi"
769590075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
769690075Sobrien	(minus:SI (match_operand:SI 1 "s_register_operand" "r")
769790075Sobrien		  (match_operator:SI 2 "shift_operator"
769890075Sobrien		   [(match_operand:SI 3 "s_register_operand" "r")
769990075Sobrien		    (match_operand:SI 4 "reg_or_int_operand" "rM")])))]
770090075Sobrien  "TARGET_ARM"
770190075Sobrien  "sub%?\\t%0, %1, %3%S2"
770290075Sobrien  [(set_attr "predicable" "yes")
770390075Sobrien   (set_attr "shift" "3")
770490075Sobrien   ]
770590075Sobrien)
770690075Sobrien
770790075Sobrien(define_insn "*sub_shiftsi_compare0"
770890075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
770990075Sobrien	(compare:CC_NOOV
771090075Sobrien	 (minus:SI (match_operand:SI 1 "s_register_operand" "r")
771190075Sobrien		   (match_operator:SI 2 "shift_operator"
771290075Sobrien		    [(match_operand:SI 3 "s_register_operand" "r")
771390075Sobrien		     (match_operand:SI 4 "reg_or_int_operand" "rM")]))
771490075Sobrien	 (const_int 0)))
771590075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
771690075Sobrien	(minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3)
771790075Sobrien						 (match_dup 4)])))]
771890075Sobrien  "TARGET_ARM"
771990075Sobrien  "sub%?s\\t%0, %1, %3%S2"
772090075Sobrien  [(set_attr "conds" "set")
772190075Sobrien   (set_attr "shift" "3") 
772290075Sobrien   ]
772390075Sobrien)
772490075Sobrien
772590075Sobrien(define_insn "*sub_shiftsi_compare0_scratch"
772690075Sobrien  [(set (reg:CC_NOOV CC_REGNUM)
772790075Sobrien	(compare:CC_NOOV
772890075Sobrien	 (minus:SI (match_operand:SI 1 "s_register_operand" "r")
772990075Sobrien		   (match_operator:SI 2 "shift_operator"
773090075Sobrien		    [(match_operand:SI 3 "s_register_operand" "r")
773190075Sobrien		     (match_operand:SI 4 "reg_or_int_operand" "rM")]))
773290075Sobrien	 (const_int 0)))
773390075Sobrien   (clobber (match_scratch:SI 0 "=r"))]
773490075Sobrien  "TARGET_ARM"
773590075Sobrien  "sub%?s\\t%0, %1, %3%S2"
773690075Sobrien  [(set_attr "conds" "set")
773790075Sobrien   (set_attr "shift" "3") 
773890075Sobrien   ]
773990075Sobrien)
774090075Sobrien
774190075Sobrien
774290075Sobrien
774390075Sobrien(define_insn "*and_scc"
774490075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
774590075Sobrien	(and:SI (match_operator:SI 1 "arm_comparison_operator"
774690075Sobrien		 [(match_operand 3 "cc_register" "") (const_int 0)])
774790075Sobrien		(match_operand:SI 2 "s_register_operand" "r")))]
774890075Sobrien  "TARGET_ARM"
774990075Sobrien  "mov%D1\\t%0, #0\;and%d1\\t%0, %2, #1"
775090075Sobrien  [(set_attr "conds" "use")
775190075Sobrien   (set_attr "length" "8")]
775290075Sobrien)
775390075Sobrien
775490075Sobrien(define_insn "*ior_scc"
775590075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
775690075Sobrien	(ior:SI (match_operator:SI 2 "arm_comparison_operator"
775790075Sobrien		 [(match_operand 3 "cc_register" "") (const_int 0)])
775890075Sobrien		(match_operand:SI 1 "s_register_operand" "0,?r")))]
775990075Sobrien  "TARGET_ARM"
776090075Sobrien  "@
776190075Sobrien   orr%d2\\t%0, %1, #1
776290075Sobrien   mov%D2\\t%0, %1\;orr%d2\\t%0, %1, #1"
776390075Sobrien  [(set_attr "conds" "use")
776490075Sobrien   (set_attr "length" "4,8")]
776590075Sobrien)
776690075Sobrien
776790075Sobrien(define_insn "*compare_scc"
776890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
776990075Sobrien	(match_operator:SI 1 "arm_comparison_operator"
777090075Sobrien	 [(match_operand:SI 2 "s_register_operand" "r,r")
777190075Sobrien	  (match_operand:SI 3 "arm_add_operand" "rI,L")]))
777290075Sobrien   (clobber (reg:CC CC_REGNUM))]
777390075Sobrien  "TARGET_ARM"
777490075Sobrien  "*
777590075Sobrien    if (operands[3] == const0_rtx)
777690075Sobrien      {
7777132718Skan	if (GET_CODE (operands[1]) == LT)
7778132718Skan	  return \"mov\\t%0, %2, lsr #31\";
7779132718Skan
7780132718Skan	if (GET_CODE (operands[1]) == GE)
778190075Sobrien	  return \"mvn\\t%0, %2\;mov\\t%0, %0, lsr #31\";
7782132718Skan
7783132718Skan	if (GET_CODE (operands[1]) == EQ)
778490075Sobrien	  return \"rsbs\\t%0, %2, #1\;movcc\\t%0, #0\";
7785132718Skan      }
7786132718Skan
7787132718Skan    if (GET_CODE (operands[1]) == NE)
7788132718Skan      {
778990075Sobrien        if (which_alternative == 1)
779090075Sobrien	  return \"adds\\t%0, %2, #%n3\;movne\\t%0, #1\";
779190075Sobrien        return \"subs\\t%0, %2, %3\;movne\\t%0, #1\";
779290075Sobrien      }
779390075Sobrien    if (which_alternative == 1)
779490075Sobrien      output_asm_insn (\"cmn\\t%2, #%n3\", operands);
779590075Sobrien    else
779690075Sobrien      output_asm_insn (\"cmp\\t%2, %3\", operands);
779790075Sobrien    return \"mov%D1\\t%0, #0\;mov%d1\\t%0, #1\";
779890075Sobrien  "
779990075Sobrien  [(set_attr "conds" "clob")
780090075Sobrien   (set_attr "length" "12")]
780190075Sobrien)
780290075Sobrien
780390075Sobrien(define_insn "*cond_move"
780490075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
780590075Sobrien	(if_then_else:SI (match_operator 3 "equality_operator"
780690075Sobrien			  [(match_operator 4 "arm_comparison_operator"
780790075Sobrien			    [(match_operand 5 "cc_register" "") (const_int 0)])
780890075Sobrien			   (const_int 0)])
780990075Sobrien			 (match_operand:SI 1 "arm_rhs_operand" "0,rI,?rI")
781090075Sobrien			 (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")))]
781190075Sobrien  "TARGET_ARM"
781290075Sobrien  "*
781390075Sobrien    if (GET_CODE (operands[3]) == NE)
781490075Sobrien      {
781590075Sobrien        if (which_alternative != 1)
781690075Sobrien	  output_asm_insn (\"mov%D4\\t%0, %2\", operands);
781790075Sobrien        if (which_alternative != 0)
781890075Sobrien	  output_asm_insn (\"mov%d4\\t%0, %1\", operands);
781990075Sobrien        return \"\";
782090075Sobrien      }
782190075Sobrien    if (which_alternative != 0)
782290075Sobrien      output_asm_insn (\"mov%D4\\t%0, %1\", operands);
782390075Sobrien    if (which_alternative != 1)
782490075Sobrien      output_asm_insn (\"mov%d4\\t%0, %2\", operands);
782590075Sobrien    return \"\";
782690075Sobrien  "
782790075Sobrien  [(set_attr "conds" "use")
782890075Sobrien   (set_attr "length" "4,4,8")]
782990075Sobrien)
783090075Sobrien
783190075Sobrien(define_insn "*cond_arith"
783290075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
783390075Sobrien        (match_operator:SI 5 "shiftable_operator" 
783490075Sobrien	 [(match_operator:SI 4 "arm_comparison_operator"
783590075Sobrien           [(match_operand:SI 2 "s_register_operand" "r,r")
783690075Sobrien	    (match_operand:SI 3 "arm_rhs_operand" "rI,rI")])
783790075Sobrien          (match_operand:SI 1 "s_register_operand" "0,?r")]))
783890075Sobrien   (clobber (reg:CC CC_REGNUM))]
783990075Sobrien  "TARGET_ARM"
784090075Sobrien  "*
784190075Sobrien    if (GET_CODE (operands[4]) == LT && operands[3] == const0_rtx)
784290075Sobrien      return \"%i5\\t%0, %1, %2, lsr #31\";
784390075Sobrien
784490075Sobrien    output_asm_insn (\"cmp\\t%2, %3\", operands);
784590075Sobrien    if (GET_CODE (operands[5]) == AND)
784690075Sobrien      output_asm_insn (\"mov%D4\\t%0, #0\", operands);
784790075Sobrien    else if (GET_CODE (operands[5]) == MINUS)
784890075Sobrien      output_asm_insn (\"rsb%D4\\t%0, %1, #0\", operands);
784990075Sobrien    else if (which_alternative != 0)
785090075Sobrien      output_asm_insn (\"mov%D4\\t%0, %1\", operands);
785190075Sobrien    return \"%i5%d4\\t%0, %1, #1\";
785290075Sobrien  "
785390075Sobrien  [(set_attr "conds" "clob")
785490075Sobrien   (set_attr "length" "12")]
785590075Sobrien)
785690075Sobrien
785790075Sobrien(define_insn "*cond_sub"
785890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
785990075Sobrien        (minus:SI (match_operand:SI 1 "s_register_operand" "0,?r")
786090075Sobrien		  (match_operator:SI 4 "arm_comparison_operator"
786190075Sobrien                   [(match_operand:SI 2 "s_register_operand" "r,r")
786290075Sobrien		    (match_operand:SI 3 "arm_rhs_operand" "rI,rI")])))
786390075Sobrien   (clobber (reg:CC CC_REGNUM))]
786490075Sobrien  "TARGET_ARM"
786590075Sobrien  "*
786690075Sobrien    output_asm_insn (\"cmp\\t%2, %3\", operands);
786790075Sobrien    if (which_alternative != 0)
786890075Sobrien      output_asm_insn (\"mov%D4\\t%0, %1\", operands);
786990075Sobrien    return \"sub%d4\\t%0, %1, #1\";
787090075Sobrien  "
787190075Sobrien  [(set_attr "conds" "clob")
787290075Sobrien   (set_attr "length" "8,12")]
787390075Sobrien)
787490075Sobrien
787590075Sobrien(define_insn "*cmp_ite0"
787690075Sobrien  [(set (match_operand 6 "dominant_cc_register" "")
787790075Sobrien	(compare
787890075Sobrien	 (if_then_else:SI
787990075Sobrien	  (match_operator 4 "arm_comparison_operator"
788090075Sobrien	   [(match_operand:SI 0 "s_register_operand" "r,r,r,r")
788190075Sobrien	    (match_operand:SI 1 "arm_add_operand" "rI,L,rI,L")])
788290075Sobrien	  (match_operator:SI 5 "arm_comparison_operator"
788390075Sobrien	   [(match_operand:SI 2 "s_register_operand" "r,r,r,r")
788490075Sobrien	    (match_operand:SI 3 "arm_add_operand" "rI,rI,L,L")])
788590075Sobrien	  (const_int 0))
788690075Sobrien	 (const_int 0)))]
788790075Sobrien  "TARGET_ARM"
788890075Sobrien  "*
788990075Sobrien  {
789090075Sobrien    static const char * const opcodes[4][2] =
789190075Sobrien    {
789290075Sobrien      {\"cmp\\t%2, %3\;cmp%d5\\t%0, %1\",
789390075Sobrien       \"cmp\\t%0, %1\;cmp%d4\\t%2, %3\"},
789490075Sobrien      {\"cmp\\t%2, %3\;cmn%d5\\t%0, #%n1\",
789590075Sobrien       \"cmn\\t%0, #%n1\;cmp%d4\\t%2, %3\"},
789690075Sobrien      {\"cmn\\t%2, #%n3\;cmp%d5\\t%0, %1\",
789790075Sobrien       \"cmp\\t%0, %1\;cmn%d4\\t%2, #%n3\"},
789890075Sobrien      {\"cmn\\t%2, #%n3\;cmn%d5\\t%0, #%n1\",
789990075Sobrien       \"cmn\\t%0, #%n1\;cmn%d4\\t%2, #%n3\"}
790090075Sobrien    };
790190075Sobrien    int swap =
790290075Sobrien      comparison_dominates_p (GET_CODE (operands[5]), GET_CODE (operands[4]));
790390075Sobrien
790490075Sobrien    return opcodes[which_alternative][swap];
790590075Sobrien  }"
790690075Sobrien  [(set_attr "conds" "set")
790790075Sobrien   (set_attr "length" "8")]
790890075Sobrien)
790990075Sobrien
791090075Sobrien(define_insn "*cmp_ite1"
791190075Sobrien  [(set (match_operand 6 "dominant_cc_register" "")
791290075Sobrien	(compare
791390075Sobrien	 (if_then_else:SI
791490075Sobrien	  (match_operator 4 "arm_comparison_operator"
791590075Sobrien	   [(match_operand:SI 0 "s_register_operand" "r,r,r,r")
791690075Sobrien	    (match_operand:SI 1 "arm_add_operand" "rI,L,rI,L")])
791790075Sobrien	  (match_operator:SI 5 "arm_comparison_operator"
791890075Sobrien	   [(match_operand:SI 2 "s_register_operand" "r,r,r,r")
791990075Sobrien	    (match_operand:SI 3 "arm_add_operand" "rI,rI,L,L")])
792090075Sobrien	  (const_int 1))
792190075Sobrien	 (const_int 0)))]
792290075Sobrien  "TARGET_ARM"
792390075Sobrien  "*
792490075Sobrien  {
792590075Sobrien    static const char * const opcodes[4][2] =
792690075Sobrien    {
792790075Sobrien      {\"cmp\\t%0, %1\;cmp%d4\\t%2, %3\",
792890075Sobrien       \"cmp\\t%2, %3\;cmp%D5\\t%0, %1\"},
792990075Sobrien      {\"cmn\\t%0, #%n1\;cmp%d4\\t%2, %3\",
793090075Sobrien       \"cmp\\t%2, %3\;cmn%D5\\t%0, #%n1\"},
793190075Sobrien      {\"cmp\\t%0, %1\;cmn%d4\\t%2, #%n3\",
793290075Sobrien       \"cmn\\t%2, #%n3\;cmp%D5\\t%0, %1\"},
793390075Sobrien      {\"cmn\\t%0, #%n1\;cmn%d4\\t%2, #%n3\",
793490075Sobrien       \"cmn\\t%2, #%n3\;cmn%D5\\t%0, #%n1\"}
793590075Sobrien    };
793690075Sobrien    int swap =
793790075Sobrien      comparison_dominates_p (GET_CODE (operands[5]),
793890075Sobrien			      reverse_condition (GET_CODE (operands[4])));
793990075Sobrien
794090075Sobrien    return opcodes[which_alternative][swap];
794190075Sobrien  }"
794290075Sobrien  [(set_attr "conds" "set")
794390075Sobrien   (set_attr "length" "8")]
794490075Sobrien)
794590075Sobrien
794690075Sobrien(define_insn "*cmp_and"
794790075Sobrien  [(set (match_operand 6 "dominant_cc_register" "")
794890075Sobrien	(compare
794990075Sobrien	 (and:SI
795090075Sobrien	  (match_operator 4 "arm_comparison_operator"
795190075Sobrien	   [(match_operand:SI 0 "s_register_operand" "r,r,r,r")
795290075Sobrien	    (match_operand:SI 1 "arm_add_operand" "rI,L,rI,L")])
795390075Sobrien	  (match_operator:SI 5 "arm_comparison_operator"
795490075Sobrien	   [(match_operand:SI 2 "s_register_operand" "r,r,r,r")
795590075Sobrien	    (match_operand:SI 3 "arm_add_operand" "rI,rI,L,L")]))
795690075Sobrien	 (const_int 0)))]
795790075Sobrien  "TARGET_ARM"
795890075Sobrien  "*
795990075Sobrien  {
796090075Sobrien    static const char *const opcodes[4][2] =
796190075Sobrien    {
796290075Sobrien      {\"cmp\\t%2, %3\;cmp%d5\\t%0, %1\",
796390075Sobrien       \"cmp\\t%0, %1\;cmp%d4\\t%2, %3\"},
796490075Sobrien      {\"cmp\\t%2, %3\;cmn%d5\\t%0, #%n1\",
796590075Sobrien       \"cmn\\t%0, #%n1\;cmp%d4\\t%2, %3\"},
796690075Sobrien      {\"cmn\\t%2, #%n3\;cmp%d5\\t%0, %1\",
796790075Sobrien       \"cmp\\t%0, %1\;cmn%d4\\t%2, #%n3\"},
796890075Sobrien      {\"cmn\\t%2, #%n3\;cmn%d5\\t%0, #%n1\",
796990075Sobrien       \"cmn\\t%0, #%n1\;cmn%d4\\t%2, #%n3\"}
797090075Sobrien    };
797190075Sobrien    int swap =
797290075Sobrien      comparison_dominates_p (GET_CODE (operands[5]), GET_CODE (operands[4]));
797390075Sobrien
797490075Sobrien    return opcodes[which_alternative][swap];
797590075Sobrien  }"
797690075Sobrien  [(set_attr "conds" "set")
797790075Sobrien   (set_attr "predicable" "no")
797890075Sobrien   (set_attr "length" "8")]
797990075Sobrien)
798090075Sobrien
798190075Sobrien(define_insn "*cmp_ior"
798290075Sobrien  [(set (match_operand 6 "dominant_cc_register" "")
798390075Sobrien	(compare
798490075Sobrien	 (ior:SI
798590075Sobrien	  (match_operator 4 "arm_comparison_operator"
798690075Sobrien	   [(match_operand:SI 0 "s_register_operand" "r,r,r,r")
798790075Sobrien	    (match_operand:SI 1 "arm_add_operand" "rI,L,rI,L")])
798890075Sobrien	  (match_operator:SI 5 "arm_comparison_operator"
798990075Sobrien	   [(match_operand:SI 2 "s_register_operand" "r,r,r,r")
799090075Sobrien	    (match_operand:SI 3 "arm_add_operand" "rI,rI,L,L")]))
799190075Sobrien	 (const_int 0)))]
799290075Sobrien  "TARGET_ARM"
799390075Sobrien  "*
799490075Sobrien{
799590075Sobrien  static const char *const opcodes[4][2] =
799690075Sobrien  {
799790075Sobrien    {\"cmp\\t%0, %1\;cmp%D4\\t%2, %3\",
799890075Sobrien     \"cmp\\t%2, %3\;cmp%D5\\t%0, %1\"},
799990075Sobrien    {\"cmn\\t%0, #%n1\;cmp%D4\\t%2, %3\",
800090075Sobrien     \"cmp\\t%2, %3\;cmn%D5\\t%0, #%n1\"},
800190075Sobrien    {\"cmp\\t%0, %1\;cmn%D4\\t%2, #%n3\",
800290075Sobrien     \"cmn\\t%2, #%n3\;cmp%D5\\t%0, %1\"},
800390075Sobrien    {\"cmn\\t%0, #%n1\;cmn%D4\\t%2, #%n3\",
800490075Sobrien     \"cmn\\t%2, #%n3\;cmn%D5\\t%0, #%n1\"}
800590075Sobrien  };
800690075Sobrien  int swap =
800790075Sobrien    comparison_dominates_p (GET_CODE (operands[5]), GET_CODE (operands[4]));
800890075Sobrien
800990075Sobrien  return opcodes[which_alternative][swap];
801090075Sobrien}
801190075Sobrien"
801290075Sobrien  [(set_attr "conds" "set")
801390075Sobrien   (set_attr "length" "8")]
801490075Sobrien)
801590075Sobrien
801690075Sobrien(define_insn_and_split "*ior_scc_scc"
801790075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
8018132718Skan	(ior:SI (match_operator:SI 3 "arm_comparison_operator"
8019132718Skan		 [(match_operand:SI 1 "s_register_operand" "r")
8020132718Skan		  (match_operand:SI 2 "arm_add_operand" "rIL")])
8021132718Skan		(match_operator:SI 6 "arm_comparison_operator"
8022132718Skan		 [(match_operand:SI 4 "s_register_operand" "r")
8023132718Skan		  (match_operand:SI 5 "arm_add_operand" "rIL")])))
8024132718Skan   (clobber (reg:CC CC_REGNUM))]
8025132718Skan  "TARGET_ARM
8026132718Skan   && (arm_select_dominance_cc_mode (operands[3], operands[6], DOM_CC_X_OR_Y)
8027132718Skan       != CCmode)"
8028132718Skan  "#"
8029132718Skan  "TARGET_ARM && reload_completed"
8030132718Skan  [(set (match_dup 7)
8031132718Skan	(compare
8032132718Skan	 (ior:SI
8033132718Skan	  (match_op_dup 3 [(match_dup 1) (match_dup 2)])
8034132718Skan	  (match_op_dup 6 [(match_dup 4) (match_dup 5)]))
8035132718Skan	 (const_int 0)))
8036132718Skan   (set (match_dup 0) (ne:SI (match_dup 7) (const_int 0)))]
8037132718Skan  "operands[7]
8038132718Skan     = gen_rtx_REG (arm_select_dominance_cc_mode (operands[3], operands[6],
8039132718Skan						  DOM_CC_X_OR_Y),
8040132718Skan		    CC_REGNUM);"
8041132718Skan  [(set_attr "conds" "clob")
8042132718Skan   (set_attr "length" "16")])
8043132718Skan
8044132718Skan; If the above pattern is followed by a CMP insn, then the compare is 
8045132718Skan; redundant, since we can rework the conditional instruction that follows.
8046132718Skan(define_insn_and_split "*ior_scc_scc_cmp"
8047132718Skan  [(set (match_operand 0 "dominant_cc_register" "")
8048132718Skan	(compare (ior:SI (match_operator:SI 3 "arm_comparison_operator"
8049132718Skan			  [(match_operand:SI 1 "s_register_operand" "r")
8050132718Skan			   (match_operand:SI 2 "arm_add_operand" "rIL")])
8051132718Skan			 (match_operator:SI 6 "arm_comparison_operator"
8052132718Skan			  [(match_operand:SI 4 "s_register_operand" "r")
8053132718Skan			   (match_operand:SI 5 "arm_add_operand" "rIL")]))
8054132718Skan		 (const_int 0)))
8055132718Skan   (set (match_operand:SI 7 "s_register_operand" "=r")
8056132718Skan	(ior:SI (match_op_dup 3 [(match_dup 1) (match_dup 2)])
8057132718Skan		(match_op_dup 6 [(match_dup 4) (match_dup 5)])))]
8058132718Skan  "TARGET_ARM"
8059132718Skan  "#"
8060132718Skan  "TARGET_ARM && reload_completed"
8061132718Skan  [(set (match_dup 0)
8062132718Skan	(compare
8063132718Skan	 (ior:SI
8064132718Skan	  (match_op_dup 3 [(match_dup 1) (match_dup 2)])
8065132718Skan	  (match_op_dup 6 [(match_dup 4) (match_dup 5)]))
8066132718Skan	 (const_int 0)))
8067132718Skan   (set (match_dup 7) (ne:SI (match_dup 0) (const_int 0)))]
8068132718Skan  ""
8069132718Skan  [(set_attr "conds" "set")
8070132718Skan   (set_attr "length" "16")])
8071132718Skan
8072132718Skan(define_insn_and_split "*and_scc_scc"
8073132718Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
8074132718Skan	(and:SI (match_operator:SI 3 "arm_comparison_operator"
8075132718Skan		 [(match_operand:SI 1 "s_register_operand" "r")
8076132718Skan		  (match_operand:SI 2 "arm_add_operand" "rIL")])
8077132718Skan		(match_operator:SI 6 "arm_comparison_operator"
8078132718Skan		 [(match_operand:SI 4 "s_register_operand" "r")
8079132718Skan		  (match_operand:SI 5 "arm_add_operand" "rIL")])))
8080132718Skan   (clobber (reg:CC CC_REGNUM))]
8081132718Skan  "TARGET_ARM
8082132718Skan   && (arm_select_dominance_cc_mode (operands[3], operands[6], DOM_CC_X_AND_Y)
8083132718Skan       != CCmode)"
8084132718Skan  "#"
8085132718Skan  "TARGET_ARM && reload_completed
8086132718Skan   && (arm_select_dominance_cc_mode (operands[3], operands[6], DOM_CC_X_AND_Y)
8087132718Skan       != CCmode)"
8088132718Skan  [(set (match_dup 7)
8089132718Skan	(compare
8090132718Skan	 (and:SI
8091132718Skan	  (match_op_dup 3 [(match_dup 1) (match_dup 2)])
8092132718Skan	  (match_op_dup 6 [(match_dup 4) (match_dup 5)]))
8093132718Skan	 (const_int 0)))
8094132718Skan   (set (match_dup 0) (ne:SI (match_dup 7) (const_int 0)))]
8095132718Skan  "operands[7]
8096132718Skan     = gen_rtx_REG (arm_select_dominance_cc_mode (operands[3], operands[6],
8097132718Skan						  DOM_CC_X_AND_Y),
8098132718Skan		    CC_REGNUM);"
8099132718Skan  [(set_attr "conds" "clob")
8100132718Skan   (set_attr "length" "16")])
8101132718Skan
8102132718Skan; If the above pattern is followed by a CMP insn, then the compare is 
8103132718Skan; redundant, since we can rework the conditional instruction that follows.
8104132718Skan(define_insn_and_split "*and_scc_scc_cmp"
8105132718Skan  [(set (match_operand 0 "dominant_cc_register" "")
8106132718Skan	(compare (and:SI (match_operator:SI 3 "arm_comparison_operator"
8107132718Skan			  [(match_operand:SI 1 "s_register_operand" "r")
8108132718Skan			   (match_operand:SI 2 "arm_add_operand" "rIL")])
8109132718Skan			 (match_operator:SI 6 "arm_comparison_operator"
8110132718Skan			  [(match_operand:SI 4 "s_register_operand" "r")
8111132718Skan			   (match_operand:SI 5 "arm_add_operand" "rIL")]))
8112132718Skan		 (const_int 0)))
8113132718Skan   (set (match_operand:SI 7 "s_register_operand" "=r")
8114132718Skan	(and:SI (match_op_dup 3 [(match_dup 1) (match_dup 2)])
8115132718Skan		(match_op_dup 6 [(match_dup 4) (match_dup 5)])))]
8116132718Skan  "TARGET_ARM"
8117132718Skan  "#"
8118132718Skan  "TARGET_ARM && reload_completed"
8119132718Skan  [(set (match_dup 0)
8120132718Skan	(compare
8121132718Skan	 (and:SI
8122132718Skan	  (match_op_dup 3 [(match_dup 1) (match_dup 2)])
8123132718Skan	  (match_op_dup 6 [(match_dup 4) (match_dup 5)]))
8124132718Skan	 (const_int 0)))
8125132718Skan   (set (match_dup 7) (ne:SI (match_dup 0) (const_int 0)))]
8126132718Skan  ""
8127132718Skan  [(set_attr "conds" "set")
8128132718Skan   (set_attr "length" "16")])
8129132718Skan
8130132718Skan;; If there is no dominance in the comparison, then we can still save an
8131132718Skan;; instruction in the AND case, since we can know that the second compare
8132132718Skan;; need only zero the value if false (if true, then the value is already
8133132718Skan;; correct).
8134132718Skan(define_insn_and_split "*and_scc_scc_nodom"
8135132718Skan  [(set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r")
8136132718Skan	(and:SI (match_operator:SI 3 "arm_comparison_operator"
8137132718Skan		 [(match_operand:SI 1 "s_register_operand" "r,r,0")
8138132718Skan		  (match_operand:SI 2 "arm_add_operand" "rIL,0,rIL")])
8139132718Skan		(match_operator:SI 6 "arm_comparison_operator"
8140132718Skan		 [(match_operand:SI 4 "s_register_operand" "r,r,r")
8141132718Skan		  (match_operand:SI 5 "arm_add_operand" "rIL,rIL,rIL")])))
8142132718Skan   (clobber (reg:CC CC_REGNUM))]
8143132718Skan  "TARGET_ARM
8144132718Skan   && (arm_select_dominance_cc_mode (operands[3], operands[6], DOM_CC_X_AND_Y)
8145132718Skan       == CCmode)"
8146132718Skan  "#"
8147132718Skan  "TARGET_ARM && reload_completed"
8148132718Skan  [(parallel [(set (match_dup 0)
8149132718Skan		   (match_op_dup 3 [(match_dup 1) (match_dup 2)]))
8150132718Skan	      (clobber (reg:CC CC_REGNUM))])
8151132718Skan   (set (match_dup 7) (match_op_dup 8 [(match_dup 4) (match_dup 5)]))
8152132718Skan   (set (match_dup 0)
8153132718Skan	(if_then_else:SI (match_op_dup 6 [(match_dup 7) (const_int 0)])
8154132718Skan			 (match_dup 0)
8155132718Skan			 (const_int 0)))]
8156132718Skan  "operands[7] = gen_rtx_REG (SELECT_CC_MODE (GET_CODE (operands[6]),
8157132718Skan					      operands[4], operands[5]),
8158132718Skan			      CC_REGNUM);
8159132718Skan   operands[8] = gen_rtx_COMPARE (GET_MODE (operands[7]), operands[4],
8160132718Skan				  operands[5]);"
8161132718Skan  [(set_attr "conds" "clob")
8162132718Skan   (set_attr "length" "20")])
8163132718Skan
8164132718Skan(define_split
8165132718Skan  [(set (reg:CC_NOOV CC_REGNUM)
8166132718Skan	(compare:CC_NOOV (ior:SI
8167132718Skan			  (and:SI (match_operand:SI 0 "s_register_operand" "")
8168132718Skan				  (const_int 1))
8169132718Skan			  (match_operator:SI 1 "comparison_operator"
8170132718Skan			   [(match_operand:SI 2 "s_register_operand" "")
8171132718Skan			    (match_operand:SI 3 "arm_add_operand" "")]))
8172132718Skan			 (const_int 0)))
8173132718Skan   (clobber (match_operand:SI 4 "s_register_operand" ""))]
8174132718Skan  "TARGET_ARM"
8175132718Skan  [(set (match_dup 4)
8176132718Skan	(ior:SI (match_op_dup 1 [(match_dup 2) (match_dup 3)])
8177132718Skan		(match_dup 0)))
8178132718Skan   (set (reg:CC_NOOV CC_REGNUM)
8179132718Skan	(compare:CC_NOOV (and:SI (match_dup 4) (const_int 1))
8180132718Skan			 (const_int 0)))]
8181132718Skan  "")
8182132718Skan
8183132718Skan(define_split
8184132718Skan  [(set (reg:CC_NOOV CC_REGNUM)
8185132718Skan	(compare:CC_NOOV (ior:SI
8186132718Skan			  (match_operator:SI 1 "comparison_operator"
8187132718Skan			   [(match_operand:SI 2 "s_register_operand" "")
8188132718Skan			    (match_operand:SI 3 "arm_add_operand" "")])
8189132718Skan			  (and:SI (match_operand:SI 0 "s_register_operand" "")
8190132718Skan				  (const_int 1)))
8191132718Skan			 (const_int 0)))
8192132718Skan   (clobber (match_operand:SI 4 "s_register_operand" ""))]
8193132718Skan  "TARGET_ARM"
8194132718Skan  [(set (match_dup 4)
8195132718Skan	(ior:SI (match_op_dup 1 [(match_dup 2) (match_dup 3)])
8196132718Skan		(match_dup 0)))
8197132718Skan   (set (reg:CC_NOOV CC_REGNUM)
8198132718Skan	(compare:CC_NOOV (and:SI (match_dup 4) (const_int 1))
8199132718Skan			 (const_int 0)))]
8200132718Skan  "")
8201132718Skan
8202132718Skan(define_insn "*negscc"
8203132718Skan  [(set (match_operand:SI 0 "s_register_operand" "=r")
820490075Sobrien	(neg:SI (match_operator 3 "arm_comparison_operator"
820590075Sobrien		 [(match_operand:SI 1 "s_register_operand" "r")
820690075Sobrien		  (match_operand:SI 2 "arm_rhs_operand" "rI")])))
820790075Sobrien   (clobber (reg:CC CC_REGNUM))]
820890075Sobrien  "TARGET_ARM"
820990075Sobrien  "*
821090075Sobrien  if (GET_CODE (operands[3]) == LT && operands[3] == const0_rtx)
821190075Sobrien    return \"mov\\t%0, %1, asr #31\";
821290075Sobrien
821390075Sobrien  if (GET_CODE (operands[3]) == NE)
821490075Sobrien    return \"subs\\t%0, %1, %2\;mvnne\\t%0, #0\";
821590075Sobrien
821690075Sobrien  if (GET_CODE (operands[3]) == GT)
821790075Sobrien    return \"subs\\t%0, %1, %2\;mvnne\\t%0, %0, asr #31\";
821890075Sobrien
821990075Sobrien  output_asm_insn (\"cmp\\t%1, %2\", operands);
822090075Sobrien  output_asm_insn (\"mov%D3\\t%0, #0\", operands);
822190075Sobrien  return \"mvn%d3\\t%0, #0\";
822290075Sobrien  "
822390075Sobrien  [(set_attr "conds" "clob")
822490075Sobrien   (set_attr "length" "12")]
822590075Sobrien)
822690075Sobrien
822790075Sobrien(define_insn "movcond"
822890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
822990075Sobrien	(if_then_else:SI
823090075Sobrien	 (match_operator 5 "arm_comparison_operator"
823190075Sobrien	  [(match_operand:SI 3 "s_register_operand" "r,r,r")
823290075Sobrien	   (match_operand:SI 4 "arm_add_operand" "rIL,rIL,rIL")])
823390075Sobrien	 (match_operand:SI 1 "arm_rhs_operand" "0,rI,?rI")
823490075Sobrien	 (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")))
823590075Sobrien   (clobber (reg:CC CC_REGNUM))]
823690075Sobrien  "TARGET_ARM"
823790075Sobrien  "*
823890075Sobrien  if (GET_CODE (operands[5]) == LT
823990075Sobrien      && (operands[4] == const0_rtx))
824090075Sobrien    {
824190075Sobrien      if (which_alternative != 1 && GET_CODE (operands[1]) == REG)
824290075Sobrien	{
824390075Sobrien	  if (operands[2] == const0_rtx)
824490075Sobrien	    return \"and\\t%0, %1, %3, asr #31\";
824590075Sobrien	  return \"ands\\t%0, %1, %3, asr #32\;movcc\\t%0, %2\";
824690075Sobrien	}
824790075Sobrien      else if (which_alternative != 0 && GET_CODE (operands[2]) == REG)
824890075Sobrien	{
824990075Sobrien	  if (operands[1] == const0_rtx)
825090075Sobrien	    return \"bic\\t%0, %2, %3, asr #31\";
825190075Sobrien	  return \"bics\\t%0, %2, %3, asr #32\;movcs\\t%0, %1\";
825290075Sobrien	}
825390075Sobrien      /* The only case that falls through to here is when both ops 1 & 2
825490075Sobrien	 are constants.  */
825590075Sobrien    }
8256132718Skan
825790075Sobrien  if (GET_CODE (operands[5]) == GE
825890075Sobrien      && (operands[4] == const0_rtx))
825990075Sobrien    {
826090075Sobrien      if (which_alternative != 1 && GET_CODE (operands[1]) == REG)
826190075Sobrien	{
826290075Sobrien	  if (operands[2] == const0_rtx)
826390075Sobrien	    return \"bic\\t%0, %1, %3, asr #31\";
826490075Sobrien	  return \"bics\\t%0, %1, %3, asr #32\;movcs\\t%0, %2\";
826590075Sobrien	}
826690075Sobrien      else if (which_alternative != 0 && GET_CODE (operands[2]) == REG)
826790075Sobrien	{
826890075Sobrien	  if (operands[1] == const0_rtx)
826990075Sobrien	    return \"and\\t%0, %2, %3, asr #31\";
827090075Sobrien	  return \"ands\\t%0, %2, %3, asr #32\;movcc\\t%0, %1\";
827190075Sobrien	}
827290075Sobrien      /* The only case that falls through to here is when both ops 1 & 2
827390075Sobrien	 are constants.  */
827490075Sobrien    }
8275132718Skan  if (GET_CODE (operands[4]) == CONST_INT
827690075Sobrien      && !const_ok_for_arm (INTVAL (operands[4])))
827790075Sobrien    output_asm_insn (\"cmn\\t%3, #%n4\", operands);
827890075Sobrien  else
827990075Sobrien    output_asm_insn (\"cmp\\t%3, %4\", operands);
828090075Sobrien  if (which_alternative != 0)
828190075Sobrien    output_asm_insn (\"mov%d5\\t%0, %1\", operands);
828290075Sobrien  if (which_alternative != 1)
828390075Sobrien    output_asm_insn (\"mov%D5\\t%0, %2\", operands);
828490075Sobrien  return \"\";
828590075Sobrien  "
828690075Sobrien  [(set_attr "conds" "clob")
828790075Sobrien   (set_attr "length" "8,8,12")]
828890075Sobrien)
828990075Sobrien
829090075Sobrien(define_insn "*ifcompare_plus_move"
829190075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
829290075Sobrien	(if_then_else:SI (match_operator 6 "arm_comparison_operator"
829390075Sobrien			  [(match_operand:SI 4 "s_register_operand" "r,r")
829490075Sobrien			   (match_operand:SI 5 "arm_add_operand" "rIL,rIL")])
829590075Sobrien			 (plus:SI
829690075Sobrien			  (match_operand:SI 2 "s_register_operand" "r,r")
829790075Sobrien			  (match_operand:SI 3 "arm_add_operand" "rIL,rIL"))
829890075Sobrien			 (match_operand:SI 1 "arm_rhs_operand" "0,?rI")))
829990075Sobrien   (clobber (reg:CC CC_REGNUM))]
830090075Sobrien  "TARGET_ARM"
830190075Sobrien  "#"
830290075Sobrien  [(set_attr "conds" "clob")
830390075Sobrien   (set_attr "length" "8,12")]
830490075Sobrien)
830590075Sobrien
830690075Sobrien(define_insn "*if_plus_move"
830790075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r")
830890075Sobrien	(if_then_else:SI
830990075Sobrien	 (match_operator 4 "arm_comparison_operator"
831090075Sobrien	  [(match_operand 5 "cc_register" "") (const_int 0)])
831190075Sobrien	 (plus:SI
831290075Sobrien	  (match_operand:SI 2 "s_register_operand" "r,r,r,r")
831390075Sobrien	  (match_operand:SI 3 "arm_add_operand" "rI,L,rI,L"))
831490075Sobrien	 (match_operand:SI 1 "arm_rhs_operand" "0,0,?rI,?rI")))]
831590075Sobrien  "TARGET_ARM"
831690075Sobrien  "@
831790075Sobrien   add%d4\\t%0, %2, %3
831890075Sobrien   sub%d4\\t%0, %2, #%n3
831990075Sobrien   add%d4\\t%0, %2, %3\;mov%D4\\t%0, %1
832090075Sobrien   sub%d4\\t%0, %2, #%n3\;mov%D4\\t%0, %1"
832190075Sobrien  [(set_attr "conds" "use")
832290075Sobrien   (set_attr "length" "4,4,8,8")
832390075Sobrien   (set_attr "type" "*,*,*,*")]
832490075Sobrien)
832590075Sobrien
832690075Sobrien(define_insn "*ifcompare_move_plus"
832790075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
832890075Sobrien	(if_then_else:SI (match_operator 6 "arm_comparison_operator"
832990075Sobrien			  [(match_operand:SI 4 "s_register_operand" "r,r")
833090075Sobrien			   (match_operand:SI 5 "arm_add_operand" "rIL,rIL")])
833190075Sobrien			 (match_operand:SI 1 "arm_rhs_operand" "0,?rI")
833290075Sobrien			 (plus:SI
833390075Sobrien			  (match_operand:SI 2 "s_register_operand" "r,r")
833490075Sobrien			  (match_operand:SI 3 "arm_add_operand" "rIL,rIL"))))
833590075Sobrien   (clobber (reg:CC CC_REGNUM))]
833690075Sobrien  "TARGET_ARM"
833790075Sobrien  "#"
833890075Sobrien  [(set_attr "conds" "clob")
833990075Sobrien   (set_attr "length" "8,12")]
834090075Sobrien)
834190075Sobrien
834290075Sobrien(define_insn "*if_move_plus"
834390075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r")
834490075Sobrien	(if_then_else:SI
834590075Sobrien	 (match_operator 4 "arm_comparison_operator"
834690075Sobrien	  [(match_operand 5 "cc_register" "") (const_int 0)])
834790075Sobrien	 (match_operand:SI 1 "arm_rhs_operand" "0,0,?rI,?rI")
834890075Sobrien	 (plus:SI
834990075Sobrien	  (match_operand:SI 2 "s_register_operand" "r,r,r,r")
835090075Sobrien	  (match_operand:SI 3 "arm_add_operand" "rI,L,rI,L"))))]
835190075Sobrien  "TARGET_ARM"
835290075Sobrien  "@
835390075Sobrien   add%D4\\t%0, %2, %3
835490075Sobrien   sub%D4\\t%0, %2, #%n3
835590075Sobrien   add%D4\\t%0, %2, %3\;mov%d4\\t%0, %1
835690075Sobrien   sub%D4\\t%0, %2, #%n3\;mov%d4\\t%0, %1"
835790075Sobrien  [(set_attr "conds" "use")
835890075Sobrien   (set_attr "length" "4,4,8,8")
835990075Sobrien   (set_attr "type" "*,*,*,*")]
836090075Sobrien)
836190075Sobrien
836290075Sobrien(define_insn "*ifcompare_arith_arith"
836390075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
836490075Sobrien	(if_then_else:SI (match_operator 9 "arm_comparison_operator"
836590075Sobrien			  [(match_operand:SI 5 "s_register_operand" "r")
836690075Sobrien			   (match_operand:SI 6 "arm_add_operand" "rIL")])
836790075Sobrien			 (match_operator:SI 8 "shiftable_operator"
836890075Sobrien			  [(match_operand:SI 1 "s_register_operand" "r")
836990075Sobrien			   (match_operand:SI 2 "arm_rhs_operand" "rI")])
837090075Sobrien			 (match_operator:SI 7 "shiftable_operator"
837190075Sobrien			  [(match_operand:SI 3 "s_register_operand" "r")
837290075Sobrien			   (match_operand:SI 4 "arm_rhs_operand" "rI")])))
837390075Sobrien   (clobber (reg:CC CC_REGNUM))]
837490075Sobrien  "TARGET_ARM"
837590075Sobrien  "#"
837690075Sobrien  [(set_attr "conds" "clob")
837790075Sobrien   (set_attr "length" "12")]
837890075Sobrien)
837990075Sobrien
838090075Sobrien(define_insn "*if_arith_arith"
838190075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
838290075Sobrien	(if_then_else:SI (match_operator 5 "arm_comparison_operator"
838390075Sobrien			  [(match_operand 8 "cc_register" "") (const_int 0)])
838490075Sobrien			 (match_operator:SI 6 "shiftable_operator"
838590075Sobrien			  [(match_operand:SI 1 "s_register_operand" "r")
838690075Sobrien			   (match_operand:SI 2 "arm_rhs_operand" "rI")])
838790075Sobrien			 (match_operator:SI 7 "shiftable_operator"
838890075Sobrien			  [(match_operand:SI 3 "s_register_operand" "r")
838990075Sobrien			   (match_operand:SI 4 "arm_rhs_operand" "rI")])))]
839090075Sobrien  "TARGET_ARM"
839190075Sobrien  "%I6%d5\\t%0, %1, %2\;%I7%D5\\t%0, %3, %4"
839290075Sobrien  [(set_attr "conds" "use")
839390075Sobrien   (set_attr "length" "8")]
839490075Sobrien)
839590075Sobrien
839690075Sobrien(define_insn "*ifcompare_arith_move"
839790075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
839890075Sobrien	(if_then_else:SI (match_operator 6 "arm_comparison_operator"
839990075Sobrien			  [(match_operand:SI 2 "s_register_operand" "r,r")
840090075Sobrien			   (match_operand:SI 3 "arm_add_operand" "rIL,rIL")])
840190075Sobrien			 (match_operator:SI 7 "shiftable_operator"
840290075Sobrien			  [(match_operand:SI 4 "s_register_operand" "r,r")
840390075Sobrien			   (match_operand:SI 5 "arm_rhs_operand" "rI,rI")])
840490075Sobrien			 (match_operand:SI 1 "arm_rhs_operand" "0,?rI")))
840590075Sobrien   (clobber (reg:CC CC_REGNUM))]
840690075Sobrien  "TARGET_ARM"
840790075Sobrien  "*
840890075Sobrien  /* If we have an operation where (op x 0) is the identity operation and
840990075Sobrien     the conditional operator is LT or GE and we are comparing against zero and
841090075Sobrien     everything is in registers then we can do this in two instructions.  */
841190075Sobrien  if (operands[3] == const0_rtx
8412132718Skan      && GET_CODE (operands[7]) != AND
841390075Sobrien      && GET_CODE (operands[5]) == REG
841490075Sobrien      && GET_CODE (operands[1]) == REG 
841590075Sobrien      && REGNO (operands[1]) == REGNO (operands[4])
841690075Sobrien      && REGNO (operands[4]) != REGNO (operands[0]))
841790075Sobrien    {
841890075Sobrien      if (GET_CODE (operands[6]) == LT)
841990075Sobrien	return \"and\\t%0, %5, %2, asr #31\;%I7\\t%0, %4, %0\";
842090075Sobrien      else if (GET_CODE (operands[6]) == GE)
842190075Sobrien	return \"bic\\t%0, %5, %2, asr #31\;%I7\\t%0, %4, %0\";
842290075Sobrien    }
842390075Sobrien  if (GET_CODE (operands[3]) == CONST_INT
842490075Sobrien      && !const_ok_for_arm (INTVAL (operands[3])))
842590075Sobrien    output_asm_insn (\"cmn\\t%2, #%n3\", operands);
842690075Sobrien  else
842790075Sobrien    output_asm_insn (\"cmp\\t%2, %3\", operands);
842890075Sobrien  output_asm_insn (\"%I7%d6\\t%0, %4, %5\", operands);
842990075Sobrien  if (which_alternative != 0)
843090075Sobrien    return \"mov%D6\\t%0, %1\";
843190075Sobrien  return \"\";
843290075Sobrien  "
843390075Sobrien  [(set_attr "conds" "clob")
843490075Sobrien   (set_attr "length" "8,12")]
843590075Sobrien)
843690075Sobrien
843790075Sobrien(define_insn "*if_arith_move"
843890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
843990075Sobrien	(if_then_else:SI (match_operator 4 "arm_comparison_operator"
844090075Sobrien			  [(match_operand 6 "cc_register" "") (const_int 0)])
844190075Sobrien			 (match_operator:SI 5 "shiftable_operator"
844290075Sobrien			  [(match_operand:SI 2 "s_register_operand" "r,r")
844390075Sobrien			   (match_operand:SI 3 "arm_rhs_operand" "rI,rI")])
844490075Sobrien			 (match_operand:SI 1 "arm_rhs_operand" "0,?rI")))]
844590075Sobrien  "TARGET_ARM"
844690075Sobrien  "@
844790075Sobrien   %I5%d4\\t%0, %2, %3
844890075Sobrien   %I5%d4\\t%0, %2, %3\;mov%D4\\t%0, %1"
844990075Sobrien  [(set_attr "conds" "use")
845090075Sobrien   (set_attr "length" "4,8")
845190075Sobrien   (set_attr "type" "*,*")]
845290075Sobrien)
845390075Sobrien
845490075Sobrien(define_insn "*ifcompare_move_arith"
845590075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
845690075Sobrien	(if_then_else:SI (match_operator 6 "arm_comparison_operator"
845790075Sobrien			  [(match_operand:SI 4 "s_register_operand" "r,r")
845890075Sobrien			   (match_operand:SI 5 "arm_add_operand" "rIL,rIL")])
845990075Sobrien			 (match_operand:SI 1 "arm_rhs_operand" "0,?rI")
846090075Sobrien			 (match_operator:SI 7 "shiftable_operator"
846190075Sobrien			  [(match_operand:SI 2 "s_register_operand" "r,r")
846290075Sobrien			   (match_operand:SI 3 "arm_rhs_operand" "rI,rI")])))
846390075Sobrien   (clobber (reg:CC CC_REGNUM))]
846490075Sobrien  "TARGET_ARM"
846590075Sobrien  "*
846690075Sobrien  /* If we have an operation where (op x 0) is the identity operation and
846790075Sobrien     the conditional operator is LT or GE and we are comparing against zero and
846890075Sobrien     everything is in registers then we can do this in two instructions */
846990075Sobrien  if (operands[5] == const0_rtx
847090075Sobrien      && GET_CODE (operands[7]) != AND
847190075Sobrien      && GET_CODE (operands[3]) == REG
847290075Sobrien      && GET_CODE (operands[1]) == REG 
847390075Sobrien      && REGNO (operands[1]) == REGNO (operands[2])
847490075Sobrien      && REGNO (operands[2]) != REGNO (operands[0]))
847590075Sobrien    {
847690075Sobrien      if (GET_CODE (operands[6]) == GE)
847790075Sobrien	return \"and\\t%0, %3, %4, asr #31\;%I7\\t%0, %2, %0\";
847890075Sobrien      else if (GET_CODE (operands[6]) == LT)
847990075Sobrien	return \"bic\\t%0, %3, %4, asr #31\;%I7\\t%0, %2, %0\";
848090075Sobrien    }
848190075Sobrien
848290075Sobrien  if (GET_CODE (operands[5]) == CONST_INT
848390075Sobrien      && !const_ok_for_arm (INTVAL (operands[5])))
848490075Sobrien    output_asm_insn (\"cmn\\t%4, #%n5\", operands);
848590075Sobrien  else
848690075Sobrien    output_asm_insn (\"cmp\\t%4, %5\", operands);
848790075Sobrien
848890075Sobrien  if (which_alternative != 0)
848990075Sobrien    output_asm_insn (\"mov%d6\\t%0, %1\", operands);
849090075Sobrien  return \"%I7%D6\\t%0, %2, %3\";
849190075Sobrien  "
849290075Sobrien  [(set_attr "conds" "clob")
849390075Sobrien   (set_attr "length" "8,12")]
849490075Sobrien)
849590075Sobrien
849690075Sobrien(define_insn "*if_move_arith"
849790075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
849890075Sobrien	(if_then_else:SI
849990075Sobrien	 (match_operator 4 "arm_comparison_operator"
850090075Sobrien	  [(match_operand 6 "cc_register" "") (const_int 0)])
850190075Sobrien	 (match_operand:SI 1 "arm_rhs_operand" "0,?rI")
850290075Sobrien	 (match_operator:SI 5 "shiftable_operator"
850390075Sobrien	  [(match_operand:SI 2 "s_register_operand" "r,r")
850490075Sobrien	   (match_operand:SI 3 "arm_rhs_operand" "rI,rI")])))]
850590075Sobrien  "TARGET_ARM"
850690075Sobrien  "@
850790075Sobrien   %I5%D4\\t%0, %2, %3
850890075Sobrien   %I5%D4\\t%0, %2, %3\;mov%d4\\t%0, %1"
850990075Sobrien  [(set_attr "conds" "use")
851090075Sobrien   (set_attr "length" "4,8")
851190075Sobrien   (set_attr "type" "*,*")]
851290075Sobrien)
851390075Sobrien
851490075Sobrien(define_insn "*ifcompare_move_not"
851590075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
851690075Sobrien	(if_then_else:SI
851790075Sobrien	 (match_operator 5 "arm_comparison_operator"
851890075Sobrien	  [(match_operand:SI 3 "s_register_operand" "r,r")
851990075Sobrien	   (match_operand:SI 4 "arm_add_operand" "rIL,rIL")])
852090075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rIK")
852190075Sobrien	 (not:SI
852290075Sobrien	  (match_operand:SI 2 "s_register_operand" "r,r"))))
852390075Sobrien   (clobber (reg:CC CC_REGNUM))]
852490075Sobrien  "TARGET_ARM"
852590075Sobrien  "#"
852690075Sobrien  [(set_attr "conds" "clob")
852790075Sobrien   (set_attr "length" "8,12")]
852890075Sobrien)
852990075Sobrien
853090075Sobrien(define_insn "*if_move_not"
853190075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
853290075Sobrien	(if_then_else:SI
853390075Sobrien	 (match_operator 4 "arm_comparison_operator"
853490075Sobrien	  [(match_operand 3 "cc_register" "") (const_int 0)])
853590075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rI,K")
853690075Sobrien	 (not:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))))]
853790075Sobrien  "TARGET_ARM"
853890075Sobrien  "@
853990075Sobrien   mvn%D4\\t%0, %2
854090075Sobrien   mov%d4\\t%0, %1\;mvn%D4\\t%0, %2
854190075Sobrien   mvn%d4\\t%0, #%B1\;mvn%D4\\t%0, %2"
854290075Sobrien  [(set_attr "conds" "use")
854390075Sobrien   (set_attr "length" "4,8,8")]
854490075Sobrien)
854590075Sobrien
854690075Sobrien(define_insn "*ifcompare_not_move"
854790075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
854890075Sobrien	(if_then_else:SI 
854990075Sobrien	 (match_operator 5 "arm_comparison_operator"
855090075Sobrien	  [(match_operand:SI 3 "s_register_operand" "r,r")
855190075Sobrien	   (match_operand:SI 4 "arm_add_operand" "rIL,rIL")])
855290075Sobrien	 (not:SI
855390075Sobrien	  (match_operand:SI 2 "s_register_operand" "r,r"))
855490075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rIK")))
855590075Sobrien   (clobber (reg:CC CC_REGNUM))]
855690075Sobrien  "TARGET_ARM"
855790075Sobrien  "#"
855890075Sobrien  [(set_attr "conds" "clob")
855990075Sobrien   (set_attr "length" "8,12")]
856090075Sobrien)
856190075Sobrien
856290075Sobrien(define_insn "*if_not_move"
856390075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
856490075Sobrien	(if_then_else:SI
856590075Sobrien	 (match_operator 4 "arm_comparison_operator"
856690075Sobrien	  [(match_operand 3 "cc_register" "") (const_int 0)])
856790075Sobrien	 (not:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))
856890075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))]
856990075Sobrien  "TARGET_ARM"
857090075Sobrien  "@
857190075Sobrien   mvn%d4\\t%0, %2
857290075Sobrien   mov%D4\\t%0, %1\;mvn%d4\\t%0, %2
857390075Sobrien   mvn%D4\\t%0, #%B1\;mvn%d4\\t%0, %2"
857490075Sobrien  [(set_attr "conds" "use")
857590075Sobrien   (set_attr "length" "4,8,8")]
857690075Sobrien)
857790075Sobrien
857890075Sobrien(define_insn "*ifcompare_shift_move"
857990075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
858090075Sobrien	(if_then_else:SI
858190075Sobrien	 (match_operator 6 "arm_comparison_operator"
858290075Sobrien	  [(match_operand:SI 4 "s_register_operand" "r,r")
858390075Sobrien	   (match_operand:SI 5 "arm_add_operand" "rIL,rIL")])
858490075Sobrien	 (match_operator:SI 7 "shift_operator"
858590075Sobrien	  [(match_operand:SI 2 "s_register_operand" "r,r")
858690075Sobrien	   (match_operand:SI 3 "arm_rhs_operand" "rM,rM")])
858790075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rIK")))
858890075Sobrien   (clobber (reg:CC CC_REGNUM))]
858990075Sobrien  "TARGET_ARM"
859090075Sobrien  "#"
859190075Sobrien  [(set_attr "conds" "clob")
859290075Sobrien   (set_attr "length" "8,12")]
859390075Sobrien)
859490075Sobrien
859590075Sobrien(define_insn "*if_shift_move"
859690075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
859790075Sobrien	(if_then_else:SI
859890075Sobrien	 (match_operator 5 "arm_comparison_operator"
859990075Sobrien	  [(match_operand 6 "cc_register" "") (const_int 0)])
860090075Sobrien	 (match_operator:SI 4 "shift_operator"
860190075Sobrien	  [(match_operand:SI 2 "s_register_operand" "r,r,r")
860290075Sobrien	   (match_operand:SI 3 "arm_rhs_operand" "rM,rM,rM")])
860390075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))]
860490075Sobrien  "TARGET_ARM"
860590075Sobrien  "@
860690075Sobrien   mov%d5\\t%0, %2%S4
860790075Sobrien   mov%D5\\t%0, %1\;mov%d5\\t%0, %2%S4
860890075Sobrien   mvn%D5\\t%0, #%B1\;mov%d5\\t%0, %2%S4"
860990075Sobrien  [(set_attr "conds" "use")
861090075Sobrien   (set_attr "shift" "2")
861190075Sobrien   (set_attr "length" "4,8,8")]
861290075Sobrien)
861390075Sobrien
861490075Sobrien(define_insn "*ifcompare_move_shift"
861590075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
861690075Sobrien	(if_then_else:SI
861790075Sobrien	 (match_operator 6 "arm_comparison_operator"
861890075Sobrien	  [(match_operand:SI 4 "s_register_operand" "r,r")
861990075Sobrien	   (match_operand:SI 5 "arm_add_operand" "rIL,rIL")])
862090075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rIK")
862190075Sobrien	 (match_operator:SI 7 "shift_operator"
862290075Sobrien	  [(match_operand:SI 2 "s_register_operand" "r,r")
862390075Sobrien	   (match_operand:SI 3 "arm_rhs_operand" "rM,rM")])))
862490075Sobrien   (clobber (reg:CC CC_REGNUM))]
862590075Sobrien  "TARGET_ARM"
862690075Sobrien  "#"
862790075Sobrien  [(set_attr "conds" "clob")
862890075Sobrien   (set_attr "length" "8,12")]
862990075Sobrien)
863090075Sobrien
863190075Sobrien(define_insn "*if_move_shift"
863290075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
863390075Sobrien	(if_then_else:SI
863490075Sobrien	 (match_operator 5 "arm_comparison_operator"
863590075Sobrien	  [(match_operand 6 "cc_register" "") (const_int 0)])
863690075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rI,K")
863790075Sobrien	 (match_operator:SI 4 "shift_operator"
863890075Sobrien	  [(match_operand:SI 2 "s_register_operand" "r,r,r")
863990075Sobrien	   (match_operand:SI 3 "arm_rhs_operand" "rM,rM,rM")])))]
864090075Sobrien  "TARGET_ARM"
864190075Sobrien  "@
864290075Sobrien   mov%D5\\t%0, %2%S4
864390075Sobrien   mov%d5\\t%0, %1\;mov%D5\\t%0, %2%S4
864490075Sobrien   mvn%d5\\t%0, #%B1\;mov%D5\\t%0, %2%S4"
864590075Sobrien  [(set_attr "conds" "use")
864690075Sobrien   (set_attr "shift" "2")
864790075Sobrien   (set_attr "length" "4,8,8")]
864890075Sobrien)
864990075Sobrien
865090075Sobrien(define_insn "*ifcompare_shift_shift"
865190075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
865290075Sobrien	(if_then_else:SI
865390075Sobrien	 (match_operator 7 "arm_comparison_operator"
865490075Sobrien	  [(match_operand:SI 5 "s_register_operand" "r")
865590075Sobrien	   (match_operand:SI 6 "arm_add_operand" "rIL")])
865690075Sobrien	 (match_operator:SI 8 "shift_operator"
865790075Sobrien	  [(match_operand:SI 1 "s_register_operand" "r")
865890075Sobrien	   (match_operand:SI 2 "arm_rhs_operand" "rM")])
865990075Sobrien	 (match_operator:SI 9 "shift_operator"
866090075Sobrien	  [(match_operand:SI 3 "s_register_operand" "r")
866190075Sobrien	   (match_operand:SI 4 "arm_rhs_operand" "rM")])))
866290075Sobrien   (clobber (reg:CC CC_REGNUM))]
866390075Sobrien  "TARGET_ARM"
866490075Sobrien  "#"
866590075Sobrien  [(set_attr "conds" "clob")
866690075Sobrien   (set_attr "length" "12")]
866790075Sobrien)
866890075Sobrien
866990075Sobrien(define_insn "*if_shift_shift"
867090075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
867190075Sobrien	(if_then_else:SI
867290075Sobrien	 (match_operator 5 "arm_comparison_operator"
867390075Sobrien	  [(match_operand 8 "cc_register" "") (const_int 0)])
867490075Sobrien	 (match_operator:SI 6 "shift_operator"
867590075Sobrien	  [(match_operand:SI 1 "s_register_operand" "r")
867690075Sobrien	   (match_operand:SI 2 "arm_rhs_operand" "rM")])
867790075Sobrien	 (match_operator:SI 7 "shift_operator"
867890075Sobrien	  [(match_operand:SI 3 "s_register_operand" "r")
867990075Sobrien	   (match_operand:SI 4 "arm_rhs_operand" "rM")])))]
868090075Sobrien  "TARGET_ARM"
868190075Sobrien  "mov%d5\\t%0, %1%S6\;mov%D5\\t%0, %3%S7"
868290075Sobrien  [(set_attr "conds" "use")
868390075Sobrien   (set_attr "shift" "1")
868490075Sobrien   (set_attr "length" "8")]
868590075Sobrien)
868690075Sobrien
868790075Sobrien(define_insn "*ifcompare_not_arith"
868890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
868990075Sobrien	(if_then_else:SI
869090075Sobrien	 (match_operator 6 "arm_comparison_operator"
869190075Sobrien	  [(match_operand:SI 4 "s_register_operand" "r")
869290075Sobrien	   (match_operand:SI 5 "arm_add_operand" "rIL")])
869390075Sobrien	 (not:SI (match_operand:SI 1 "s_register_operand" "r"))
869490075Sobrien	 (match_operator:SI 7 "shiftable_operator"
869590075Sobrien	  [(match_operand:SI 2 "s_register_operand" "r")
869690075Sobrien	   (match_operand:SI 3 "arm_rhs_operand" "rI")])))
869790075Sobrien   (clobber (reg:CC CC_REGNUM))]
869890075Sobrien  "TARGET_ARM"
869990075Sobrien  "#"
870090075Sobrien  [(set_attr "conds" "clob")
870190075Sobrien   (set_attr "length" "12")]
870290075Sobrien)
870390075Sobrien
870490075Sobrien(define_insn "*if_not_arith"
870590075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
870690075Sobrien	(if_then_else:SI
870790075Sobrien	 (match_operator 5 "arm_comparison_operator"
870890075Sobrien	  [(match_operand 4 "cc_register" "") (const_int 0)])
870990075Sobrien	 (not:SI (match_operand:SI 1 "s_register_operand" "r"))
871090075Sobrien	 (match_operator:SI 6 "shiftable_operator"
871190075Sobrien	  [(match_operand:SI 2 "s_register_operand" "r")
871290075Sobrien	   (match_operand:SI 3 "arm_rhs_operand" "rI")])))]
871390075Sobrien  "TARGET_ARM"
871490075Sobrien  "mvn%d5\\t%0, %1\;%I6%D5\\t%0, %2, %3"
871590075Sobrien  [(set_attr "conds" "use")
871690075Sobrien   (set_attr "length" "8")]
871790075Sobrien)
871890075Sobrien
871990075Sobrien(define_insn "*ifcompare_arith_not"
872090075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
872190075Sobrien	(if_then_else:SI
872290075Sobrien	 (match_operator 6 "arm_comparison_operator"
872390075Sobrien	  [(match_operand:SI 4 "s_register_operand" "r")
872490075Sobrien	   (match_operand:SI 5 "arm_add_operand" "rIL")])
872590075Sobrien	 (match_operator:SI 7 "shiftable_operator"
872690075Sobrien	  [(match_operand:SI 2 "s_register_operand" "r")
872790075Sobrien	   (match_operand:SI 3 "arm_rhs_operand" "rI")])
872890075Sobrien	 (not:SI (match_operand:SI 1 "s_register_operand" "r"))))
872990075Sobrien   (clobber (reg:CC CC_REGNUM))]
873090075Sobrien  "TARGET_ARM"
873190075Sobrien  "#"
873290075Sobrien  [(set_attr "conds" "clob")
873390075Sobrien   (set_attr "length" "12")]
873490075Sobrien)
873590075Sobrien
873690075Sobrien(define_insn "*if_arith_not"
873790075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
873890075Sobrien	(if_then_else:SI
873990075Sobrien	 (match_operator 5 "arm_comparison_operator"
874090075Sobrien	  [(match_operand 4 "cc_register" "") (const_int 0)])
874190075Sobrien	 (match_operator:SI 6 "shiftable_operator"
874290075Sobrien	  [(match_operand:SI 2 "s_register_operand" "r")
874390075Sobrien	   (match_operand:SI 3 "arm_rhs_operand" "rI")])
874490075Sobrien	 (not:SI (match_operand:SI 1 "s_register_operand" "r"))))]
874590075Sobrien  "TARGET_ARM"
874690075Sobrien  "mvn%D5\\t%0, %1\;%I6%d5\\t%0, %2, %3"
874790075Sobrien  [(set_attr "conds" "use")
874890075Sobrien   (set_attr "length" "8")]
874990075Sobrien)
875090075Sobrien
875190075Sobrien(define_insn "*ifcompare_neg_move"
875290075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
875390075Sobrien	(if_then_else:SI
875490075Sobrien	 (match_operator 5 "arm_comparison_operator"
875590075Sobrien	  [(match_operand:SI 3 "s_register_operand" "r,r")
875690075Sobrien	   (match_operand:SI 4 "arm_add_operand" "rIL,rIL")])
875790075Sobrien	 (neg:SI (match_operand:SI 2 "s_register_operand" "r,r"))
875890075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rIK")))
875990075Sobrien   (clobber (reg:CC CC_REGNUM))]
876090075Sobrien  "TARGET_ARM"
876190075Sobrien  "#"
876290075Sobrien  [(set_attr "conds" "clob")
876390075Sobrien   (set_attr "length" "8,12")]
876490075Sobrien)
876590075Sobrien
876690075Sobrien(define_insn "*if_neg_move"
876790075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
876890075Sobrien	(if_then_else:SI
876990075Sobrien	 (match_operator 4 "arm_comparison_operator"
877090075Sobrien	  [(match_operand 3 "cc_register" "") (const_int 0)])
877190075Sobrien	 (neg:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))
877290075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))]
877390075Sobrien  "TARGET_ARM"
877490075Sobrien  "@
877590075Sobrien   rsb%d4\\t%0, %2, #0
877690075Sobrien   mov%D4\\t%0, %1\;rsb%d4\\t%0, %2, #0
877790075Sobrien   mvn%D4\\t%0, #%B1\;rsb%d4\\t%0, %2, #0"
877890075Sobrien  [(set_attr "conds" "use")
877990075Sobrien   (set_attr "length" "4,8,8")]
878090075Sobrien)
878190075Sobrien
878290075Sobrien(define_insn "*ifcompare_move_neg"
878390075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
878490075Sobrien	(if_then_else:SI
878590075Sobrien	 (match_operator 5 "arm_comparison_operator"
878690075Sobrien	  [(match_operand:SI 3 "s_register_operand" "r,r")
878790075Sobrien	   (match_operand:SI 4 "arm_add_operand" "rIL,rIL")])
878890075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rIK")
878990075Sobrien	 (neg:SI (match_operand:SI 2 "s_register_operand" "r,r"))))
879090075Sobrien   (clobber (reg:CC CC_REGNUM))]
879190075Sobrien  "TARGET_ARM"
879290075Sobrien  "#"
879390075Sobrien  [(set_attr "conds" "clob")
879490075Sobrien   (set_attr "length" "8,12")]
879590075Sobrien)
879690075Sobrien
879790075Sobrien(define_insn "*if_move_neg"
879890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
879990075Sobrien	(if_then_else:SI
880090075Sobrien	 (match_operator 4 "arm_comparison_operator"
880190075Sobrien	  [(match_operand 3 "cc_register" "") (const_int 0)])
880290075Sobrien	 (match_operand:SI 1 "arm_not_operand" "0,?rI,K")
880390075Sobrien	 (neg:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))))]
880490075Sobrien  "TARGET_ARM"
880590075Sobrien  "@
880690075Sobrien   rsb%D4\\t%0, %2, #0
880790075Sobrien   mov%d4\\t%0, %1\;rsb%D4\\t%0, %2, #0
880890075Sobrien   mvn%d4\\t%0, #%B1\;rsb%D4\\t%0, %2, #0"
880990075Sobrien  [(set_attr "conds" "use")
881090075Sobrien   (set_attr "length" "4,8,8")]
881190075Sobrien)
881290075Sobrien
881390075Sobrien(define_insn "*arith_adjacentmem"
881490075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
881590075Sobrien	(match_operator:SI 1 "shiftable_operator"
881690075Sobrien	 [(match_operand:SI 2 "memory_operand" "m")
881790075Sobrien	  (match_operand:SI 3 "memory_operand" "m")]))
881890075Sobrien   (clobber (match_scratch:SI 4 "=r"))]
881990075Sobrien  "TARGET_ARM && adjacent_mem_locations (operands[2], operands[3])"
882090075Sobrien  "*
882190075Sobrien  {
882290075Sobrien    rtx ldm[3];
882390075Sobrien    rtx arith[4];
882490075Sobrien    int val1 = 0, val2 = 0;
882590075Sobrien
882690075Sobrien    if (REGNO (operands[0]) > REGNO (operands[4]))
882790075Sobrien      {
882890075Sobrien	ldm[1] = operands[4];
882990075Sobrien	ldm[2] = operands[0];
883090075Sobrien      }
883190075Sobrien    else
883290075Sobrien      {
883390075Sobrien	ldm[1] = operands[0];
883490075Sobrien	ldm[2] = operands[4];
883590075Sobrien      }
883690075Sobrien    if (GET_CODE (XEXP (operands[2], 0)) != REG)
883790075Sobrien      val1 = INTVAL (XEXP (XEXP (operands[2], 0), 1));
883890075Sobrien    if (GET_CODE (XEXP (operands[3], 0)) != REG)
883990075Sobrien      val2 = INTVAL (XEXP (XEXP (operands[3], 0), 1));
884090075Sobrien    arith[0] = operands[0];
884190075Sobrien    arith[3] = operands[1];
884290075Sobrien    if (val1 < val2)
884390075Sobrien      {
884490075Sobrien	arith[1] = ldm[1];
884590075Sobrien	arith[2] = ldm[2];
884690075Sobrien      }
884790075Sobrien    else
884890075Sobrien      {
884990075Sobrien	arith[1] = ldm[2];
885090075Sobrien	arith[2] = ldm[1];
885190075Sobrien      }
885290075Sobrien   if (val1 && val2)
885390075Sobrien      {
885490075Sobrien	rtx ops[3];
885590075Sobrien	ldm[0] = ops[0] = operands[4];
885690075Sobrien	ops[1] = XEXP (XEXP (operands[2], 0), 0);
885790075Sobrien	ops[2] = XEXP (XEXP (operands[2], 0), 1);
885890075Sobrien	output_add_immediate (ops);
885990075Sobrien	if (val1 < val2)
886090075Sobrien	  output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm);
886190075Sobrien	else
886290075Sobrien	  output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm);
886390075Sobrien      }
886490075Sobrien    else if (val1)
886590075Sobrien      {
886690075Sobrien	ldm[0] = XEXP (operands[3], 0);
886790075Sobrien	if (val1 < val2)
886890075Sobrien	  output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm);
886990075Sobrien	else
887090075Sobrien	  output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm);
887190075Sobrien      }
887290075Sobrien    else
887390075Sobrien      {
887490075Sobrien	ldm[0] = XEXP (operands[2], 0);
887590075Sobrien	if (val1 < val2)
887690075Sobrien	  output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm);
887790075Sobrien	else
887890075Sobrien	  output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm);
887990075Sobrien      }
888090075Sobrien    output_asm_insn (\"%I3%?\\t%0, %1, %2\", arith);
888190075Sobrien    return \"\";
888290075Sobrien  }"
888390075Sobrien  [(set_attr "length" "12")
888490075Sobrien   (set_attr "predicable" "yes")
888590075Sobrien   (set_attr "type" "load")]
888690075Sobrien)
888790075Sobrien
888890075Sobrien;; the arm can support extended pre-inc instructions
888990075Sobrien
889090075Sobrien;; In all these cases, we use operands 0 and 1 for the register being
889190075Sobrien;; incremented because those are the operands that local-alloc will
889290075Sobrien;; tie and these are the pair most likely to be tieable (and the ones
889390075Sobrien;; that will benefit the most).
889490075Sobrien
889590075Sobrien;; We reject the frame pointer if it occurs anywhere in these patterns since
889690075Sobrien;; elimination will cause too many headaches.
889790075Sobrien
889890075Sobrien(define_insn "*strqi_preinc"
889990075Sobrien  [(set (mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
890090075Sobrien			 (match_operand:SI 2 "index_operand" "rJ")))
890190075Sobrien	(match_operand:QI 3 "s_register_operand" "r"))
890290075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
890390075Sobrien	(plus:SI (match_dup 1) (match_dup 2)))]
890490075Sobrien  "TARGET_ARM
890590075Sobrien   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
890690075Sobrien   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
890790075Sobrien   && (GET_CODE (operands[2]) != REG
890890075Sobrien       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
890990075Sobrien  "str%?b\\t%3, [%0, %2]!"
891090075Sobrien  [(set_attr "type" "store1")
891190075Sobrien   (set_attr "predicable" "yes")]
891290075Sobrien)
891390075Sobrien
891490075Sobrien(define_insn "*strqi_predec"
891590075Sobrien  [(set (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
891690075Sobrien			  (match_operand:SI 2 "s_register_operand" "r")))
891790075Sobrien	(match_operand:QI 3 "s_register_operand" "r"))
891890075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
891990075Sobrien	(minus:SI (match_dup 1) (match_dup 2)))]
892090075Sobrien  "TARGET_ARM
892190075Sobrien   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
892290075Sobrien   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
892390075Sobrien   && (GET_CODE (operands[2]) != REG
892490075Sobrien       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
892590075Sobrien  "str%?b\\t%3, [%0, -%2]!"
892690075Sobrien  [(set_attr "type" "store1")
892790075Sobrien   (set_attr "predicable" "yes")]
892890075Sobrien)
892990075Sobrien
893090075Sobrien(define_insn "*loadqi_preinc"
893190075Sobrien  [(set (match_operand:QI 3 "s_register_operand" "=r")
893290075Sobrien	(mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
893390075Sobrien			 (match_operand:SI 2 "index_operand" "rJ"))))
893490075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
893590075Sobrien	(plus:SI (match_dup 1) (match_dup 2)))]
893690075Sobrien  "TARGET_ARM
893790075Sobrien   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
893890075Sobrien   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
893990075Sobrien   && (GET_CODE (operands[2]) != REG
894090075Sobrien       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
894190075Sobrien  "ldr%?b\\t%3, [%0, %2]!"
894290075Sobrien  [(set_attr "type" "load")
894390075Sobrien   (set_attr "predicable" "yes")]
894490075Sobrien)
894590075Sobrien
894690075Sobrien(define_insn "*loadqi_predec"
894790075Sobrien  [(set (match_operand:QI 3 "s_register_operand" "=r")
894890075Sobrien	(mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
894990075Sobrien			  (match_operand:SI 2 "s_register_operand" "r"))))
895090075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
895190075Sobrien	(minus:SI (match_dup 1) (match_dup 2)))]
895290075Sobrien  "TARGET_ARM
895390075Sobrien   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
895490075Sobrien   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
895590075Sobrien   && (GET_CODE (operands[2]) != REG
895690075Sobrien       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
895790075Sobrien  "ldr%?b\\t%3, [%0, -%2]!"
895890075Sobrien  [(set_attr "type" "load")
895990075Sobrien   (set_attr "predicable" "yes")]
896090075Sobrien)
896190075Sobrien
896290075Sobrien(define_insn "*loadqisi_preinc"
896390075Sobrien  [(set (match_operand:SI 3 "s_register_operand" "=r")
896490075Sobrien	(zero_extend:SI
896590075Sobrien	 (mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
896690075Sobrien			  (match_operand:SI 2 "index_operand" "rJ")))))
896790075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
896890075Sobrien	(plus:SI (match_dup 1) (match_dup 2)))]
896990075Sobrien  "TARGET_ARM
897090075Sobrien   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
897190075Sobrien   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
897290075Sobrien   && (GET_CODE (operands[2]) != REG
897390075Sobrien       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
897490075Sobrien  "ldr%?b\\t%3, [%0, %2]!\\t%@ z_extendqisi"
897590075Sobrien  [(set_attr "type" "load")
897690075Sobrien   (set_attr "predicable" "yes")]
897790075Sobrien)
897890075Sobrien
897990075Sobrien(define_insn "*loadqisi_predec"
898090075Sobrien  [(set (match_operand:SI 3 "s_register_operand" "=r")
898190075Sobrien	(zero_extend:SI
898290075Sobrien	 (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
898390075Sobrien			   (match_operand:SI 2 "s_register_operand" "r")))))
898490075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
898590075Sobrien	(minus:SI (match_dup 1) (match_dup 2)))]
898690075Sobrien  "TARGET_ARM
898790075Sobrien   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
898890075Sobrien   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
898990075Sobrien   && (GET_CODE (operands[2]) != REG
899090075Sobrien       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
899190075Sobrien  "ldr%?b\\t%3, [%0, -%2]!\\t%@ z_extendqisi"
899290075Sobrien  [(set_attr "type" "load")
899390075Sobrien   (set_attr "predicable" "yes")]
899490075Sobrien)
899590075Sobrien
899690075Sobrien(define_insn "*strsi_preinc"
899790075Sobrien  [(set (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
899890075Sobrien			 (match_operand:SI 2 "index_operand" "rJ")))
899990075Sobrien	(match_operand:SI 3 "s_register_operand" "r"))
900090075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
900190075Sobrien	(plus:SI (match_dup 1) (match_dup 2)))]
900290075Sobrien  "TARGET_ARM
900390075Sobrien   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
900490075Sobrien   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
900590075Sobrien   && (GET_CODE (operands[2]) != REG
900690075Sobrien       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
900790075Sobrien  "str%?\\t%3, [%0, %2]!"
900890075Sobrien  [(set_attr "type" "store1")
900990075Sobrien   (set_attr "predicable" "yes")]
901090075Sobrien)
901190075Sobrien
901290075Sobrien(define_insn "*strsi_predec"
901390075Sobrien  [(set (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
901490075Sobrien			  (match_operand:SI 2 "s_register_operand" "r")))
901590075Sobrien	(match_operand:SI 3 "s_register_operand" "r"))
901690075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
901790075Sobrien	(minus:SI (match_dup 1) (match_dup 2)))]
901890075Sobrien  "TARGET_ARM
901990075Sobrien   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
902090075Sobrien   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
902190075Sobrien   && (GET_CODE (operands[2]) != REG
902290075Sobrien       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
902390075Sobrien  "str%?\\t%3, [%0, -%2]!"
902490075Sobrien  [(set_attr "type" "store1")
902590075Sobrien   (set_attr "predicable" "yes")]
902690075Sobrien)
902790075Sobrien
902890075Sobrien(define_insn "*loadsi_preinc"
902990075Sobrien  [(set (match_operand:SI 3 "s_register_operand" "=r")
903090075Sobrien	(mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
903190075Sobrien			 (match_operand:SI 2 "index_operand" "rJ"))))
903290075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
903390075Sobrien	(plus:SI (match_dup 1) (match_dup 2)))]
903490075Sobrien  "TARGET_ARM
903590075Sobrien   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
903690075Sobrien   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
903790075Sobrien   && (GET_CODE (operands[2]) != REG
903890075Sobrien       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
903990075Sobrien  "ldr%?\\t%3, [%0, %2]!"
904090075Sobrien  [(set_attr "type" "load")
904190075Sobrien   (set_attr "predicable" "yes")]
904290075Sobrien)
904390075Sobrien
904490075Sobrien(define_insn "*loadsi_predec"
904590075Sobrien  [(set (match_operand:SI 3 "s_register_operand" "=r")
904690075Sobrien	(mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
904790075Sobrien			  (match_operand:SI 2 "s_register_operand" "r"))))
904890075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
904990075Sobrien	(minus:SI (match_dup 1) (match_dup 2)))]
905090075Sobrien  "TARGET_ARM
905190075Sobrien   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
905290075Sobrien   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
905390075Sobrien   && (GET_CODE (operands[2]) != REG
905490075Sobrien       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
905590075Sobrien  "ldr%?\\t%3, [%0, -%2]!"
905690075Sobrien  [(set_attr "type" "load")
905790075Sobrien   (set_attr "predicable" "yes")]
905890075Sobrien)
905990075Sobrien
906090075Sobrien(define_insn "*loadhi_preinc"
906190075Sobrien  [(set (match_operand:HI 3 "s_register_operand" "=r")
906290075Sobrien	(mem:HI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
906390075Sobrien			 (match_operand:SI 2 "index_operand" "rJ"))))
906490075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
906590075Sobrien	(plus:SI (match_dup 1) (match_dup 2)))]
906690075Sobrien  "TARGET_ARM
906790075Sobrien   && !BYTES_BIG_ENDIAN
906890075Sobrien   && !TARGET_MMU_TRAPS
906990075Sobrien   && !arm_arch4
907090075Sobrien   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
907196263Sobrien   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
907290075Sobrien   && (GET_CODE (operands[2]) != REG
907390075Sobrien       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
907490075Sobrien  "ldr%?\\t%3, [%0, %2]!\\t%@ loadhi"
907590075Sobrien  [(set_attr "type" "load")
907690075Sobrien   (set_attr "predicable" "yes")]
907790075Sobrien)
907890075Sobrien
907990075Sobrien(define_insn "*loadhi_predec"
908090075Sobrien  [(set (match_operand:HI 3 "s_register_operand" "=r")
908190075Sobrien	(mem:HI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
908290075Sobrien			  (match_operand:SI 2 "s_register_operand" "r"))))
908390075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
908490075Sobrien	(minus:SI (match_dup 1) (match_dup 2)))]
908590075Sobrien  "TARGET_ARM
908690075Sobrien   && !BYTES_BIG_ENDIAN
908790075Sobrien   && !TARGET_MMU_TRAPS
908890075Sobrien   && !arm_arch4
908990075Sobrien   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
909096263Sobrien   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
909190075Sobrien   && (GET_CODE (operands[2]) != REG
909290075Sobrien       || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
909390075Sobrien  "ldr%?\\t%3, [%0, -%2]!\\t%@ loadhi"
909490075Sobrien  [(set_attr "type" "load")
909590075Sobrien   (set_attr "predicable" "yes")]
909690075Sobrien)
909790075Sobrien
909890075Sobrien(define_insn "*strqi_shiftpreinc"
909990075Sobrien  [(set (mem:QI (plus:SI (match_operator:SI 2 "shift_operator"
910090075Sobrien			  [(match_operand:SI 3 "s_register_operand" "r")
910190075Sobrien			   (match_operand:SI 4 "const_shift_operand" "n")])
910290075Sobrien			 (match_operand:SI 1 "s_register_operand" "0")))
910390075Sobrien	(match_operand:QI 5 "s_register_operand" "r"))
910490075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
910590075Sobrien	(plus:SI (match_op_dup 2 [(match_dup 3)	(match_dup 4)])
910690075Sobrien		 (match_dup 1)))]
910790075Sobrien  "TARGET_ARM
910890075Sobrien   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
910990075Sobrien   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
911090075Sobrien   && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
911190075Sobrien  "str%?b\\t%5, [%0, %3%S2]!"
911290075Sobrien  [(set_attr "type" "store1")
911390075Sobrien   (set_attr "predicable" "yes")]
911490075Sobrien)
911590075Sobrien
911690075Sobrien(define_insn "*strqi_shiftpredec"
911790075Sobrien  [(set (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
911890075Sobrien			  (match_operator:SI 2 "shift_operator"
911990075Sobrien			   [(match_operand:SI 3 "s_register_operand" "r")
912090075Sobrien			    (match_operand:SI 4 "const_shift_operand" "n")])))
912190075Sobrien	(match_operand:QI 5 "s_register_operand" "r"))
912290075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
912390075Sobrien	(minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3)
912490075Sobrien						 (match_dup 4)])))]
912590075Sobrien  "TARGET_ARM
912690075Sobrien   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
912790075Sobrien   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
912890075Sobrien   && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
912990075Sobrien  "str%?b\\t%5, [%0, -%3%S2]!"
913090075Sobrien  [(set_attr "type" "store1")
913190075Sobrien   (set_attr "predicable" "yes")]
913290075Sobrien)
913390075Sobrien
913490075Sobrien(define_insn "*loadqi_shiftpreinc"
913590075Sobrien  [(set (match_operand:QI 5 "s_register_operand" "=r")
913690075Sobrien	(mem:QI (plus:SI (match_operator:SI 2 "shift_operator"
913790075Sobrien			  [(match_operand:SI 3 "s_register_operand" "r")
913890075Sobrien			   (match_operand:SI 4 "const_shift_operand" "n")])
913990075Sobrien			 (match_operand:SI 1 "s_register_operand" "0"))))
914090075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
914190075Sobrien	(plus:SI (match_op_dup 2 [(match_dup 3)	(match_dup 4)])
914290075Sobrien		 (match_dup 1)))]
914390075Sobrien  "TARGET_ARM
914490075Sobrien   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
914590075Sobrien   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
914690075Sobrien   && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
914790075Sobrien  "ldr%?b\\t%5, [%0, %3%S2]!"
914890075Sobrien  [(set_attr "type" "load")
914990075Sobrien   (set_attr "predicable" "yes")]
915090075Sobrien)
915190075Sobrien
915290075Sobrien(define_insn "*loadqi_shiftpredec"
915390075Sobrien  [(set (match_operand:QI 5 "s_register_operand" "=r")
915490075Sobrien	(mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
915590075Sobrien			  (match_operator:SI 2 "shift_operator"
915690075Sobrien			   [(match_operand:SI 3 "s_register_operand" "r")
915790075Sobrien			    (match_operand:SI 4 "const_shift_operand" "n")]))))
915890075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
915990075Sobrien	(minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3)
916090075Sobrien						 (match_dup 4)])))]
916190075Sobrien  "TARGET_ARM
916290075Sobrien   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
916390075Sobrien   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
916490075Sobrien   && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
916590075Sobrien  "ldr%?b\\t%5, [%0, -%3%S2]!"
916690075Sobrien  [(set_attr "type" "load")
916790075Sobrien   (set_attr "predicable" "yes")]
916890075Sobrien)
916990075Sobrien
917090075Sobrien(define_insn "*strsi_shiftpreinc"
917190075Sobrien  [(set (mem:SI (plus:SI (match_operator:SI 2 "shift_operator"
917290075Sobrien			  [(match_operand:SI 3 "s_register_operand" "r")
917390075Sobrien			   (match_operand:SI 4 "const_shift_operand" "n")])
917490075Sobrien			 (match_operand:SI 1 "s_register_operand" "0")))
917590075Sobrien	(match_operand:SI 5 "s_register_operand" "r"))
917690075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
917790075Sobrien	(plus:SI (match_op_dup 2 [(match_dup 3)	(match_dup 4)])
917890075Sobrien		 (match_dup 1)))]
917990075Sobrien  "TARGET_ARM
918090075Sobrien   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
918190075Sobrien   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
918290075Sobrien   && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
918390075Sobrien  "str%?\\t%5, [%0, %3%S2]!"
918490075Sobrien  [(set_attr "type" "store1")
918590075Sobrien   (set_attr "predicable" "yes")]
918690075Sobrien)
918790075Sobrien
918890075Sobrien(define_insn "*strsi_shiftpredec"
918990075Sobrien  [(set (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
919090075Sobrien			  (match_operator:SI 2 "shift_operator"
919190075Sobrien			   [(match_operand:SI 3 "s_register_operand" "r")
919290075Sobrien			    (match_operand:SI 4 "const_shift_operand" "n")])))
919390075Sobrien	(match_operand:SI 5 "s_register_operand" "r"))
919490075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
919590075Sobrien	(minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3)
919690075Sobrien						 (match_dup 4)])))]
919790075Sobrien  "TARGET_ARM
919890075Sobrien   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
919990075Sobrien   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
920090075Sobrien   && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
920190075Sobrien  "str%?\\t%5, [%0, -%3%S2]!"
920290075Sobrien  [(set_attr "type" "store1")
920390075Sobrien   (set_attr "predicable" "yes")]
920490075Sobrien)
920590075Sobrien
920690075Sobrien(define_insn "*loadsi_shiftpreinc"
920790075Sobrien  [(set (match_operand:SI 5 "s_register_operand" "=r")
920890075Sobrien	(mem:SI (plus:SI (match_operator:SI 2 "shift_operator"
920990075Sobrien			  [(match_operand:SI 3 "s_register_operand" "r")
921090075Sobrien			   (match_operand:SI 4 "const_shift_operand" "n")])
921190075Sobrien			 (match_operand:SI 1 "s_register_operand" "0"))))
921290075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
921390075Sobrien	(plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)])
921490075Sobrien		 (match_dup 1)))]
921590075Sobrien  "TARGET_ARM
921690075Sobrien   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
921790075Sobrien   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
921890075Sobrien   && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
921990075Sobrien  "ldr%?\\t%5, [%0, %3%S2]!"
922090075Sobrien  [(set_attr "type" "load")
922190075Sobrien   (set_attr "predicable" "yes")]
922290075Sobrien)
922390075Sobrien
922490075Sobrien(define_insn "*loadsi_shiftpredec"
922590075Sobrien  [(set (match_operand:SI 5 "s_register_operand" "=r")
922690075Sobrien	(mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
922790075Sobrien			  (match_operator:SI 2 "shift_operator"
922890075Sobrien			   [(match_operand:SI 3 "s_register_operand" "r")
922990075Sobrien			    (match_operand:SI 4 "const_shift_operand" "n")]))))
923090075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
923190075Sobrien	(minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3)
923290075Sobrien						 (match_dup 4)])))]
923390075Sobrien  "TARGET_ARM
923490075Sobrien   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
923590075Sobrien   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
923690075Sobrien   && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
923790075Sobrien  "ldr%?\\t%5, [%0, -%3%S2]!"
923890075Sobrien  [(set_attr "type" "load")
923990075Sobrien   (set_attr "predicable" "yes")])
924090075Sobrien
924190075Sobrien(define_insn "*loadhi_shiftpreinc"
924290075Sobrien  [(set (match_operand:HI 5 "s_register_operand" "=r")
924390075Sobrien	(mem:HI (plus:SI (match_operator:SI 2 "shift_operator"
924490075Sobrien			  [(match_operand:SI 3 "s_register_operand" "r")
924590075Sobrien			   (match_operand:SI 4 "const_shift_operand" "n")])
924690075Sobrien			 (match_operand:SI 1 "s_register_operand" "0"))))
924790075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
924890075Sobrien	(plus:SI (match_op_dup 2 [(match_dup 3)	(match_dup 4)])
924990075Sobrien		 (match_dup 1)))]
925090075Sobrien  "TARGET_ARM
925190075Sobrien   && !BYTES_BIG_ENDIAN
925290075Sobrien   && !TARGET_MMU_TRAPS
925390075Sobrien   && !arm_arch4
925490075Sobrien   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
925596263Sobrien   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
925690075Sobrien   && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
925790075Sobrien  "ldr%?\\t%5, [%0, %3%S2]!\\t%@ loadhi"
925890075Sobrien  [(set_attr "type" "load")
925990075Sobrien   (set_attr "predicable" "yes")]
926090075Sobrien)
926190075Sobrien
926290075Sobrien(define_insn "*loadhi_shiftpredec"
926390075Sobrien  [(set (match_operand:HI 5 "s_register_operand" "=r")
926490075Sobrien	(mem:HI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
926590075Sobrien			  (match_operator:SI 2 "shift_operator"
926690075Sobrien			   [(match_operand:SI 3 "s_register_operand" "r")
926790075Sobrien			    (match_operand:SI 4 "const_shift_operand" "n")]))))
926890075Sobrien   (set (match_operand:SI 0 "s_register_operand" "=r")
926990075Sobrien	(minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3)
927090075Sobrien						 (match_dup 4)])))]
927190075Sobrien  "TARGET_ARM
927290075Sobrien   && !BYTES_BIG_ENDIAN
927390075Sobrien   && !TARGET_MMU_TRAPS
927490075Sobrien   && !arm_arch4
927590075Sobrien   && REGNO (operands[0]) != FRAME_POINTER_REGNUM
927696263Sobrien   && REGNO (operands[1]) != FRAME_POINTER_REGNUM
927790075Sobrien   && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
927890075Sobrien  "ldr%?\\t%5, [%0, -%3%S2]!\\t%@ loadhi"
927990075Sobrien  [(set_attr "type" "load")
928090075Sobrien   (set_attr "predicable" "yes")]
928190075Sobrien)
928290075Sobrien
928390075Sobrien; It can also support extended post-inc expressions, but combine doesn't
928490075Sobrien; try these....
928590075Sobrien; It doesn't seem worth adding peepholes for anything but the most common
928690075Sobrien; cases since, unlike combine, the increment must immediately follow the load
928790075Sobrien; for this pattern to match.
928890075Sobrien; We must watch to see that the source/destination register isn't also the
928990075Sobrien; same as the base address register, and that if the index is a register,
929090075Sobrien; that it is not the same as the base address register.  In such cases the
929190075Sobrien; instruction that we would generate would have UNPREDICTABLE behavior so 
929290075Sobrien; we cannot use it.
9293117395Skan
929490075Sobrien(define_peephole
929590075Sobrien  [(set (mem:QI (match_operand:SI 0 "s_register_operand" "+r"))
929690075Sobrien	(match_operand:QI 2 "s_register_operand" "r"))
929790075Sobrien   (set (match_dup 0)
929890075Sobrien	(plus:SI (match_dup 0) (match_operand:SI 1 "index_operand" "rJ")))]
929990075Sobrien  "TARGET_ARM
930090075Sobrien   && (REGNO (operands[2]) != REGNO (operands[0]))
930190075Sobrien   && (GET_CODE (operands[1]) != REG
930290075Sobrien       || (REGNO (operands[1]) != REGNO (operands[0])))"
930390075Sobrien  "str%?b\\t%2, [%0], %1"
930490075Sobrien)
930590075Sobrien
930690075Sobrien(define_peephole
930790075Sobrien  [(set (match_operand:QI 0 "s_register_operand" "=r")
930890075Sobrien	(mem:QI (match_operand:SI 1 "s_register_operand" "+r")))
930990075Sobrien   (set (match_dup 1)
931090075Sobrien	(plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))]
931190075Sobrien  "TARGET_ARM
931290075Sobrien   && REGNO (operands[0]) != REGNO(operands[1])
931390075Sobrien   && (GET_CODE (operands[2]) != REG
931490075Sobrien       || REGNO(operands[0]) != REGNO (operands[2]))"
931590075Sobrien  "ldr%?b\\t%0, [%1], %2"
931690075Sobrien)
931790075Sobrien
931890075Sobrien(define_peephole
931990075Sobrien  [(set (mem:SI (match_operand:SI 0 "s_register_operand" "+r"))
932090075Sobrien	(match_operand:SI 2 "s_register_operand" "r"))
932190075Sobrien   (set (match_dup 0)
932290075Sobrien	(plus:SI (match_dup 0) (match_operand:SI 1 "index_operand" "rJ")))]
932390075Sobrien  "TARGET_ARM
932490075Sobrien   && (REGNO (operands[2]) != REGNO (operands[0]))
932590075Sobrien   && (GET_CODE (operands[1]) != REG
932690075Sobrien       || (REGNO (operands[1]) != REGNO (operands[0])))"
932790075Sobrien  "str%?\\t%2, [%0], %1"
932890075Sobrien)
932990075Sobrien
933090075Sobrien(define_peephole
933190075Sobrien  [(set (match_operand:HI 0 "s_register_operand" "=r")
933290075Sobrien	(mem:HI (match_operand:SI 1 "s_register_operand" "+r")))
933390075Sobrien   (set (match_dup 1)
933490075Sobrien	(plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))]
933590075Sobrien  "TARGET_ARM
933690075Sobrien   && !BYTES_BIG_ENDIAN
933790075Sobrien   && !TARGET_MMU_TRAPS
933890075Sobrien   && !arm_arch4
933990075Sobrien   && REGNO (operands[0]) != REGNO(operands[1])
934096263Sobrien   && (GET_CODE (operands[2]) != REG
934190075Sobrien       || REGNO(operands[0]) != REGNO (operands[2]))"
934290075Sobrien  "ldr%?\\t%0, [%1], %2\\t%@ loadhi"
934390075Sobrien)
934490075Sobrien
934590075Sobrien(define_peephole
934690075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
934790075Sobrien	(mem:SI (match_operand:SI 1 "s_register_operand" "+r")))
934890075Sobrien   (set (match_dup 1)
934990075Sobrien	(plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))]
935090075Sobrien  "TARGET_ARM
935190075Sobrien   && REGNO (operands[0]) != REGNO(operands[1])
935290075Sobrien   && (GET_CODE (operands[2]) != REG
935390075Sobrien       || REGNO(operands[0]) != REGNO (operands[2]))"
935490075Sobrien  "ldr%?\\t%0, [%1], %2"
935590075Sobrien)
935690075Sobrien
935790075Sobrien(define_peephole
935890075Sobrien  [(set (mem:QI (plus:SI (match_operand:SI 0 "s_register_operand" "+r")
935990075Sobrien			 (match_operand:SI 1 "index_operand" "rJ")))
936090075Sobrien	(match_operand:QI 2 "s_register_operand" "r"))
936190075Sobrien   (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))]
936290075Sobrien  "TARGET_ARM
936390075Sobrien   && (REGNO (operands[2]) != REGNO (operands[0]))
936490075Sobrien   && (GET_CODE (operands[1]) != REG
936590075Sobrien       || (REGNO (operands[1]) != REGNO (operands[0])))"
936690075Sobrien  "str%?b\\t%2, [%0, %1]!"
936790075Sobrien)
936890075Sobrien
936990075Sobrien(define_peephole
937090075Sobrien  [(set (mem:QI (plus:SI (match_operator:SI 4 "shift_operator"
937190075Sobrien			  [(match_operand:SI 0 "s_register_operand" "r")
937290075Sobrien			   (match_operand:SI 1 "const_int_operand" "n")])
937390075Sobrien			 (match_operand:SI 2 "s_register_operand" "+r")))
937490075Sobrien	(match_operand:QI 3 "s_register_operand" "r"))
937590075Sobrien   (set (match_dup 2) (plus:SI (match_op_dup 4 [(match_dup 0) (match_dup 1)])
937690075Sobrien			       (match_dup 2)))]
937790075Sobrien  "TARGET_ARM
937890075Sobrien   && (REGNO (operands[3]) != REGNO (operands[2]))
937990075Sobrien   && (REGNO (operands[0]) != REGNO (operands[2]))"
938090075Sobrien  "str%?b\\t%3, [%2, %0%S4]!"
938190075Sobrien)
938290075Sobrien
938390075Sobrien; This pattern is never tried by combine, so do it as a peephole
938490075Sobrien
938590075Sobrien(define_peephole2
938690075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
938790075Sobrien	(match_operand:SI 1 "s_register_operand" ""))
938890075Sobrien   (set (reg:CC CC_REGNUM)
938990075Sobrien	(compare:CC (match_dup 1) (const_int 0)))]
939090075Sobrien  "TARGET_ARM
939190075Sobrien   && (!TARGET_CIRRUS
939290075Sobrien       || (!cirrus_fp_register (operands[0], SImode)
9393132718Skan           && !cirrus_fp_register (operands[1], SImode)))
9394132718Skan  "
9395132718Skan  [(parallel [(set (reg:CC CC_REGNUM) (compare:CC (match_dup 1) (const_int 0)))
939690075Sobrien	      (set (match_dup 0) (match_dup 1))])]
939790075Sobrien  ""
939890075Sobrien)
939990075Sobrien
940090075Sobrien; Peepholes to spot possible load- and store-multiples, if the ordering is
940190075Sobrien; reversed, check that the memory references aren't volatile.
940290075Sobrien
940390075Sobrien(define_peephole
940490075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
940590075Sobrien        (match_operand:SI 4 "memory_operand" "m"))
940690075Sobrien   (set (match_operand:SI 1 "s_register_operand" "=r")
940790075Sobrien        (match_operand:SI 5 "memory_operand" "m"))
940890075Sobrien   (set (match_operand:SI 2 "s_register_operand" "=r")
940990075Sobrien        (match_operand:SI 6 "memory_operand" "m"))
941090075Sobrien   (set (match_operand:SI 3 "s_register_operand" "=r")
941190075Sobrien        (match_operand:SI 7 "memory_operand" "m"))]
941290075Sobrien  "TARGET_ARM && load_multiple_sequence (operands, 4, NULL, NULL, NULL)"
941390075Sobrien  "*
941490075Sobrien  return emit_ldm_seq (operands, 4);
941590075Sobrien  "
941690075Sobrien)
941790075Sobrien
941890075Sobrien(define_peephole
941990075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
942090075Sobrien        (match_operand:SI 3 "memory_operand" "m"))
942190075Sobrien   (set (match_operand:SI 1 "s_register_operand" "=r")
942290075Sobrien        (match_operand:SI 4 "memory_operand" "m"))
942390075Sobrien   (set (match_operand:SI 2 "s_register_operand" "=r")
942490075Sobrien        (match_operand:SI 5 "memory_operand" "m"))]
942590075Sobrien  "TARGET_ARM && load_multiple_sequence (operands, 3, NULL, NULL, NULL)"
942690075Sobrien  "*
942790075Sobrien  return emit_ldm_seq (operands, 3);
942890075Sobrien  "
942990075Sobrien)
943090075Sobrien
943190075Sobrien(define_peephole
943290075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
943390075Sobrien        (match_operand:SI 2 "memory_operand" "m"))
943490075Sobrien   (set (match_operand:SI 1 "s_register_operand" "=r")
943590075Sobrien        (match_operand:SI 3 "memory_operand" "m"))]
943690075Sobrien  "TARGET_ARM && load_multiple_sequence (operands, 2, NULL, NULL, NULL)"
943790075Sobrien  "*
943890075Sobrien  return emit_ldm_seq (operands, 2);
943990075Sobrien  "
944090075Sobrien)
944190075Sobrien
944290075Sobrien(define_peephole
944390075Sobrien  [(set (match_operand:SI 4 "memory_operand" "=m")
944490075Sobrien        (match_operand:SI 0 "s_register_operand" "r"))
944590075Sobrien   (set (match_operand:SI 5 "memory_operand" "=m")
944690075Sobrien        (match_operand:SI 1 "s_register_operand" "r"))
944790075Sobrien   (set (match_operand:SI 6 "memory_operand" "=m")
944890075Sobrien        (match_operand:SI 2 "s_register_operand" "r"))
944990075Sobrien   (set (match_operand:SI 7 "memory_operand" "=m")
945090075Sobrien        (match_operand:SI 3 "s_register_operand" "r"))]
945190075Sobrien  "TARGET_ARM && store_multiple_sequence (operands, 4, NULL, NULL, NULL)"
945290075Sobrien  "*
945390075Sobrien  return emit_stm_seq (operands, 4);
945490075Sobrien  "
945590075Sobrien)
945690075Sobrien
945790075Sobrien(define_peephole
945890075Sobrien  [(set (match_operand:SI 3 "memory_operand" "=m")
945990075Sobrien        (match_operand:SI 0 "s_register_operand" "r"))
946090075Sobrien   (set (match_operand:SI 4 "memory_operand" "=m")
946190075Sobrien        (match_operand:SI 1 "s_register_operand" "r"))
946290075Sobrien   (set (match_operand:SI 5 "memory_operand" "=m")
946390075Sobrien        (match_operand:SI 2 "s_register_operand" "r"))]
946490075Sobrien  "TARGET_ARM && store_multiple_sequence (operands, 3, NULL, NULL, NULL)"
946590075Sobrien  "*
946690075Sobrien  return emit_stm_seq (operands, 3);
946790075Sobrien  "
946890075Sobrien)
946990075Sobrien
947090075Sobrien(define_peephole
947190075Sobrien  [(set (match_operand:SI 2 "memory_operand" "=m")
947290075Sobrien        (match_operand:SI 0 "s_register_operand" "r"))
947390075Sobrien   (set (match_operand:SI 3 "memory_operand" "=m")
947490075Sobrien        (match_operand:SI 1 "s_register_operand" "r"))]
947590075Sobrien  "TARGET_ARM && store_multiple_sequence (operands, 2, NULL, NULL, NULL)"
947690075Sobrien  "*
947790075Sobrien  return emit_stm_seq (operands, 2);
947890075Sobrien  "
947990075Sobrien)
948090075Sobrien
948190075Sobrien(define_split
948290075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
948390075Sobrien	(and:SI (ge:SI (match_operand:SI 1 "s_register_operand" "")
948490075Sobrien		       (const_int 0))
948590075Sobrien		(neg:SI (match_operator:SI 2 "arm_comparison_operator"
948690075Sobrien			 [(match_operand:SI 3 "s_register_operand" "")
948790075Sobrien			  (match_operand:SI 4 "arm_rhs_operand" "")]))))
948890075Sobrien   (clobber (match_operand:SI 5 "s_register_operand" ""))]
948990075Sobrien  "TARGET_ARM"
949090075Sobrien  [(set (match_dup 5) (not:SI (ashiftrt:SI (match_dup 1) (const_int 31))))
949190075Sobrien   (set (match_dup 0) (and:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)])
949290075Sobrien			      (match_dup 5)))]
949390075Sobrien  ""
949490075Sobrien)
949590075Sobrien
949690075Sobrien;; This split can be used because CC_Z mode implies that the following
949790075Sobrien;; branch will be an equality, or an unsigned inequality, so the sign
949890075Sobrien;; extension is not needed.
949990075Sobrien
950090075Sobrien(define_split
950190075Sobrien  [(set (reg:CC_Z CC_REGNUM)
950290075Sobrien	(compare:CC_Z
950390075Sobrien	 (ashift:SI (subreg:SI (match_operand:QI 0 "memory_operand" "") 0)
950490075Sobrien		    (const_int 24))
950590075Sobrien	 (match_operand 1 "const_int_operand" "")))
950690075Sobrien   (clobber (match_scratch:SI 2 ""))]
950790075Sobrien  "TARGET_ARM
950890075Sobrien   && (((unsigned HOST_WIDE_INT) INTVAL (operands[1]))
950990075Sobrien       == (((unsigned HOST_WIDE_INT) INTVAL (operands[1])) >> 24) << 24)"
951090075Sobrien  [(set (match_dup 2) (zero_extend:SI (match_dup 0)))
951190075Sobrien   (set (reg:CC CC_REGNUM) (compare:CC (match_dup 2) (match_dup 1)))]
951290075Sobrien  "
951390075Sobrien  operands[1] = GEN_INT (((unsigned long) INTVAL (operands[1])) >> 24);
951490075Sobrien  "
951590075Sobrien)
951690075Sobrien
951790075Sobrien(define_expand "prologue"
951890075Sobrien  [(clobber (const_int 0))]
951990075Sobrien  "TARGET_EITHER"
952090075Sobrien  "if (TARGET_ARM)
952190075Sobrien     arm_expand_prologue ();
952290075Sobrien   else
952390075Sobrien     thumb_expand_prologue ();
952490075Sobrien  DONE;
952590075Sobrien  "
952690075Sobrien)
952790075Sobrien
952890075Sobrien(define_expand "epilogue"
952990075Sobrien  [(unspec_volatile [(return)] VUNSPEC_EPILOGUE)]
953090075Sobrien  "TARGET_EITHER"
953190075Sobrien  "
953290075Sobrien  if (TARGET_THUMB)
953390075Sobrien    thumb_expand_epilogue ();
953490075Sobrien  else if (USE_RETURN_INSN (FALSE))
953590075Sobrien    {
953690075Sobrien      emit_jump_insn (gen_return ());
953790075Sobrien      DONE;
953890075Sobrien    }
953990075Sobrien  emit_jump_insn (gen_rtx_UNSPEC_VOLATILE (VOIDmode,
954090075Sobrien	gen_rtvec (1,
954190075Sobrien		gen_rtx_RETURN (VOIDmode)),
954290075Sobrien	VUNSPEC_EPILOGUE));
954390075Sobrien  DONE;
954490075Sobrien  "
954590075Sobrien)
954690075Sobrien
954790075Sobrien;; Note - although unspec_volatile's USE all hard registers,
954890075Sobrien;; USEs are ignored after relaod has completed.  Thus we need
9549117395Skan;; to add an unspec of the link register to ensure that flow
9550117395Skan;; does not think that it is unused by the sibcall branch that
9551117395Skan;; will replace the standard function epilogue.
9552117395Skan(define_insn "sibcall_epilogue"
9553117395Skan  [(parallel [(unspec:SI [(reg:SI LR_REGNUM)] UNSPEC_PROLOGUE_USE)
955490075Sobrien              (unspec_volatile [(return)] VUNSPEC_EPILOGUE)])]
9555117395Skan  "TARGET_ARM"
9556117395Skan  "*
955790075Sobrien  if (use_return_insn (FALSE, next_nonnote_insn (insn)))
955890075Sobrien    return output_return_instruction (const_true_rtx, FALSE, FALSE);
9559132718Skan  return arm_output_epilogue (next_nonnote_insn (insn));
9560117395Skan  "
9561132718Skan;; Length is absolute worst case
956290075Sobrien  [(set_attr "length" "44")
956390075Sobrien   (set_attr "type" "block")
956490075Sobrien   ;; We don't clobber the conditions, but the potential length of this
9565117395Skan   ;; operation is sufficient to make conditionalizing the sequence 
9566117395Skan   ;; unlikely to be profitable.
9567117395Skan   (set_attr "conds" "clob")]
9568117395Skan)
9569117395Skan
957090075Sobrien(define_insn "*epilogue_insns"
957190075Sobrien  [(unspec_volatile [(return)] VUNSPEC_EPILOGUE)]
957290075Sobrien  "TARGET_EITHER"
957390075Sobrien  "*
957490075Sobrien  if (TARGET_ARM)
957590075Sobrien    return arm_output_epilogue (NULL);
957690075Sobrien  else /* TARGET_THUMB */
9577132718Skan    return thumb_unexpanded_epilogue ();
957890075Sobrien  "
957990075Sobrien  ; Length is absolute worst case
958090075Sobrien  [(set_attr "length" "44")
958190075Sobrien   (set_attr "type" "block")
958290075Sobrien   ;; We don't clobber the conditions, but the potential length of this
9583117395Skan   ;; operation is sufficient to make conditionalizing the sequence 
9584117395Skan   ;; unlikely to be profitable.
9585117395Skan   (set_attr "conds" "clob")]
9586117395Skan)
9587117395Skan
958890075Sobrien(define_expand "eh_epilogue"
958990075Sobrien  [(use (match_operand:SI 0 "register_operand" ""))
959090075Sobrien   (use (match_operand:SI 1 "register_operand" ""))
9591132718Skan   (use (match_operand:SI 2 "register_operand" ""))]
9592132718Skan  "TARGET_EITHER"
9593132718Skan  "
959490075Sobrien  {
959590075Sobrien    cfun->machine->eh_epilogue_sp_ofs = operands[1];
959690075Sobrien    if (GET_CODE (operands[2]) != REG || REGNO (operands[2]) != 2)
959790075Sobrien      {
959890075Sobrien	rtx ra = gen_rtx_REG (Pmode, 2);
959990075Sobrien
960090075Sobrien	emit_move_insn (ra, operands[2]);
960190075Sobrien	operands[2] = ra;
960290075Sobrien      }
960390075Sobrien    /* This is a hack -- we may have crystalized the function type too
960490075Sobrien       early.  */
960590075Sobrien    cfun->machine->func_type = 0;
960690075Sobrien  }"
960790075Sobrien)
960890075Sobrien
960990075Sobrien;; This split is only used during output to reduce the number of patterns
961090075Sobrien;; that need assembler instructions adding to them.  We allowed the setting
961190075Sobrien;; of the conditions to be implicit during rtl generation so that
961290075Sobrien;; the conditional compare patterns would work.  However this conflicts to
961390075Sobrien;; some extent with the conditional data operations, so we have to split them
961490075Sobrien;; up again here.
961590075Sobrien
961690075Sobrien(define_split
961790075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
961890075Sobrien	(if_then_else:SI (match_operator 1 "arm_comparison_operator"
961990075Sobrien			  [(match_operand 2 "" "") (match_operand 3 "" "")])
962090075Sobrien			 (match_dup 0)
962190075Sobrien			 (match_operand 4 "" "")))
962290075Sobrien   (clobber (reg:CC CC_REGNUM))]
962390075Sobrien  "TARGET_ARM && reload_completed"
962490075Sobrien  [(set (match_dup 5) (match_dup 6))
962590075Sobrien   (cond_exec (match_dup 7)
962690075Sobrien	      (set (match_dup 0) (match_dup 4)))]
962790075Sobrien  "
962890075Sobrien  {
962990075Sobrien    enum machine_mode mode = SELECT_CC_MODE (GET_CODE (operands[1]),
963090075Sobrien					     operands[2], operands[3]);
963190075Sobrien    enum rtx_code rc = GET_CODE (operands[1]);
963290075Sobrien
963390075Sobrien    operands[5] = gen_rtx_REG (mode, CC_REGNUM);
963490075Sobrien    operands[6] = gen_rtx_COMPARE (mode, operands[2], operands[3]);
963590075Sobrien    if (mode == CCFPmode || mode == CCFPEmode)
963690075Sobrien      rc = reverse_condition_maybe_unordered (rc);
963790075Sobrien    else
963890075Sobrien      rc = reverse_condition (rc);
963990075Sobrien
964090075Sobrien    operands[7] = gen_rtx_fmt_ee (rc, VOIDmode, operands[5], const0_rtx);
964190075Sobrien  }"
964290075Sobrien)
964390075Sobrien
964490075Sobrien(define_split
964590075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
964690075Sobrien	(if_then_else:SI (match_operator 1 "arm_comparison_operator"
964790075Sobrien			  [(match_operand 2 "" "") (match_operand 3 "" "")])
964890075Sobrien			 (match_operand 4 "" "")
964990075Sobrien			 (match_dup 0)))
965090075Sobrien   (clobber (reg:CC CC_REGNUM))]
965190075Sobrien  "TARGET_ARM && reload_completed"
965290075Sobrien  [(set (match_dup 5) (match_dup 6))
965390075Sobrien   (cond_exec (match_op_dup 1 [(match_dup 5) (const_int 0)])
965490075Sobrien	      (set (match_dup 0) (match_dup 4)))]
965590075Sobrien  "
965690075Sobrien  {
965790075Sobrien    enum machine_mode mode = SELECT_CC_MODE (GET_CODE (operands[1]),
965890075Sobrien					     operands[2], operands[3]);
965990075Sobrien
966090075Sobrien    operands[5] = gen_rtx_REG (mode, CC_REGNUM);
966190075Sobrien    operands[6] = gen_rtx_COMPARE (mode, operands[2], operands[3]);
966290075Sobrien  }"
966390075Sobrien)
966490075Sobrien
966590075Sobrien(define_split
966690075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
966790075Sobrien	(if_then_else:SI (match_operator 1 "arm_comparison_operator"
966890075Sobrien			  [(match_operand 2 "" "") (match_operand 3 "" "")])
966990075Sobrien			 (match_operand 4 "" "")
967090075Sobrien			 (match_operand 5 "" "")))
967190075Sobrien   (clobber (reg:CC CC_REGNUM))]
967290075Sobrien  "TARGET_ARM && reload_completed"
967390075Sobrien  [(set (match_dup 6) (match_dup 7))
967490075Sobrien   (cond_exec (match_op_dup 1 [(match_dup 6) (const_int 0)])
967590075Sobrien	      (set (match_dup 0) (match_dup 4)))
967690075Sobrien   (cond_exec (match_dup 8)
967790075Sobrien	      (set (match_dup 0) (match_dup 5)))]
967890075Sobrien  "
967990075Sobrien  {
968090075Sobrien    enum machine_mode mode = SELECT_CC_MODE (GET_CODE (operands[1]),
968190075Sobrien					     operands[2], operands[3]);
968290075Sobrien    enum rtx_code rc = GET_CODE (operands[1]);
968390075Sobrien
968490075Sobrien    operands[6] = gen_rtx_REG (mode, CC_REGNUM);
968590075Sobrien    operands[7] = gen_rtx_COMPARE (mode, operands[2], operands[3]);
968690075Sobrien    if (mode == CCFPmode || mode == CCFPEmode)
968790075Sobrien      rc = reverse_condition_maybe_unordered (rc);
968890075Sobrien    else
968990075Sobrien      rc = reverse_condition (rc);
969090075Sobrien
969190075Sobrien    operands[8] = gen_rtx_fmt_ee (rc, VOIDmode, operands[6], const0_rtx);
969290075Sobrien  }"
969390075Sobrien)
969490075Sobrien
969590075Sobrien(define_split
969690075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
969790075Sobrien	(if_then_else:SI (match_operator 1 "arm_comparison_operator"
969890075Sobrien			  [(match_operand:SI 2 "s_register_operand" "")
969990075Sobrien			   (match_operand:SI 3 "arm_add_operand" "")])
970090075Sobrien			 (match_operand:SI 4 "arm_rhs_operand" "")
970190075Sobrien			 (not:SI
970290075Sobrien			  (match_operand:SI 5 "s_register_operand" ""))))
970390075Sobrien   (clobber (reg:CC CC_REGNUM))]
970490075Sobrien  "TARGET_ARM && reload_completed"
970590075Sobrien  [(set (match_dup 6) (match_dup 7))
970690075Sobrien   (cond_exec (match_op_dup 1 [(match_dup 6) (const_int 0)])
970790075Sobrien	      (set (match_dup 0) (match_dup 4)))
970890075Sobrien   (cond_exec (match_dup 8)
970990075Sobrien	      (set (match_dup 0) (not:SI (match_dup 5))))]
971090075Sobrien  "
971190075Sobrien  {
971290075Sobrien    enum machine_mode mode = SELECT_CC_MODE (GET_CODE (operands[1]),
971390075Sobrien					     operands[2], operands[3]);
971490075Sobrien    enum rtx_code rc = GET_CODE (operands[1]);
971590075Sobrien
971690075Sobrien    operands[6] = gen_rtx_REG (mode, CC_REGNUM);
971790075Sobrien    operands[7] = gen_rtx (COMPARE, mode, operands[2], operands[3]);
971890075Sobrien    if (mode == CCFPmode || mode == CCFPEmode)
971990075Sobrien      rc = reverse_condition_maybe_unordered (rc);
972090075Sobrien    else
972190075Sobrien      rc = reverse_condition (rc);
972290075Sobrien
972390075Sobrien    operands[8] = gen_rtx_fmt_ee (rc, VOIDmode, operands[6], const0_rtx);
972490075Sobrien  }"
972590075Sobrien)
972690075Sobrien
972790075Sobrien(define_insn "*cond_move_not"
972890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r,r")
972990075Sobrien	(if_then_else:SI (match_operator 4 "arm_comparison_operator"
973090075Sobrien			  [(match_operand 3 "cc_register" "") (const_int 0)])
973190075Sobrien			 (match_operand:SI 1 "arm_rhs_operand" "0,?rI")
973290075Sobrien			 (not:SI
973390075Sobrien			  (match_operand:SI 2 "s_register_operand" "r,r"))))]
973490075Sobrien  "TARGET_ARM"
973590075Sobrien  "@
973690075Sobrien   mvn%D4\\t%0, %2
973790075Sobrien   mov%d4\\t%0, %1\;mvn%D4\\t%0, %2"
973890075Sobrien  [(set_attr "conds" "use")
973990075Sobrien   (set_attr "length" "4,8")]
974090075Sobrien)
974190075Sobrien
974290075Sobrien;; The next two patterns occur when an AND operation is followed by a
974390075Sobrien;; scc insn sequence 
974490075Sobrien
974590075Sobrien(define_insn "*sign_extract_onebit"
974690075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
974790075Sobrien	(sign_extract:SI (match_operand:SI 1 "s_register_operand" "r")
974890075Sobrien			 (const_int 1)
974990075Sobrien			 (match_operand:SI 2 "const_int_operand" "n")))
975090075Sobrien    (clobber (reg:CC CC_REGNUM))]
9751104752Skan  "TARGET_ARM"
9752104752Skan  "*
975390075Sobrien    operands[2] = GEN_INT (1 << INTVAL (operands[2]));
975490075Sobrien    output_asm_insn (\"ands\\t%0, %1, %2\", operands);
975590075Sobrien    return \"mvnne\\t%0, #0\";
975690075Sobrien  "
975790075Sobrien  [(set_attr "conds" "clob")
975890075Sobrien   (set_attr "length" "8")]
975990075Sobrien)
976090075Sobrien
976190075Sobrien(define_insn "*not_signextract_onebit"
976290075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
976390075Sobrien	(not:SI
976490075Sobrien	 (sign_extract:SI (match_operand:SI 1 "s_register_operand" "r")
976590075Sobrien			  (const_int 1)
976690075Sobrien			  (match_operand:SI 2 "const_int_operand" "n"))))
976790075Sobrien   (clobber (reg:CC CC_REGNUM))]
9768104752Skan  "TARGET_ARM"
9769104752Skan  "*
977090075Sobrien    operands[2] = GEN_INT (1 << INTVAL (operands[2]));
977190075Sobrien    output_asm_insn (\"tst\\t%1, %2\", operands);
977290075Sobrien    output_asm_insn (\"mvneq\\t%0, #0\", operands);
977390075Sobrien    return \"movne\\t%0, #0\";
977490075Sobrien  "
977590075Sobrien  [(set_attr "conds" "clob")
977690075Sobrien   (set_attr "length" "12")]
977790075Sobrien)
977890075Sobrien
977990075Sobrien;; Push multiple registers to the stack.  Registers are in parallel (use ...)
978090075Sobrien;; expressions.  For simplicity, the first register is also in the unspec
978190075Sobrien;; part.
978290075Sobrien(define_insn "*push_multi"
978390075Sobrien  [(match_parallel 2 "multi_register_push"
978490075Sobrien    [(set (match_operand:BLK 0 "memory_operand" "=m")
978590075Sobrien	  (unspec:BLK [(match_operand:SI 1 "s_register_operand" "r")]
978690075Sobrien		      UNSPEC_PUSH_MULT))])]
978790075Sobrien  "TARGET_ARM"
978890075Sobrien  "*
978990075Sobrien  {
979090075Sobrien    int num_saves = XVECLEN (operands[2], 0);
979190075Sobrien     
979290075Sobrien    /* For the StrongARM at least it is faster to
979390075Sobrien       use STR to store only a single register.  */
979490075Sobrien    if (num_saves == 1)
979590075Sobrien      output_asm_insn (\"str\\t%1, [%m0, #-4]!\", operands);
979690075Sobrien    else
979790075Sobrien      {
979890075Sobrien	int i;
979990075Sobrien	char pattern[100];
980090075Sobrien
980190075Sobrien	strcpy (pattern, \"stmfd\\t%m0!, {%1\");
980290075Sobrien
980390075Sobrien	for (i = 1; i < num_saves; i++)
980490075Sobrien	  {
980590075Sobrien	    strcat (pattern, \", %|\");
980690075Sobrien	    strcat (pattern,
980790075Sobrien		    reg_names[REGNO (XEXP (XVECEXP (operands[2], 0, i), 0))]);
980890075Sobrien	  }
980990075Sobrien
981090075Sobrien	strcat (pattern, \"}\");
981190075Sobrien	output_asm_insn (pattern, operands);
981290075Sobrien      }
981390075Sobrien
981490075Sobrien    return \"\";
981590075Sobrien  }"
981690075Sobrien  [(set_attr "type" "store4")]
981790075Sobrien)
981890075Sobrien
981990075Sobrien(define_insn "stack_tie"
982090075Sobrien  [(set (mem:BLK (scratch))
9821117395Skan	(unspec:BLK [(match_operand:SI 0 "s_register_operand" "r")
9822117395Skan		     (match_operand:SI 1 "s_register_operand" "r")]
9823117395Skan		    UNSPEC_PRLG_STK))]
9824117395Skan  ""
9825117395Skan  ""
9826117395Skan  [(set_attr "length" "0")]
9827117395Skan)
9828117395Skan
9829117395Skan;; Similarly for the floating point registers
9830117395Skan(define_insn "*push_fp_multi"
983190075Sobrien  [(match_parallel 2 "multi_register_push"
983290075Sobrien    [(set (match_operand:BLK 0 "memory_operand" "=m")
983390075Sobrien	  (unspec:BLK [(match_operand:XF 1 "f_register_operand" "f")]
983490075Sobrien		      UNSPEC_PUSH_MULT))])]
983590075Sobrien  "TARGET_ARM"
983690075Sobrien  "*
983790075Sobrien  {
983890075Sobrien    char pattern[100];
983990075Sobrien
984090075Sobrien    sprintf (pattern, \"sfmfd\\t%%1, %d, [%%m0]!\", XVECLEN (operands[2], 0));
984190075Sobrien    output_asm_insn (pattern, operands);
984290075Sobrien    return \"\";
984390075Sobrien  }"
984490075Sobrien  [(set_attr "type" "f_store")]
984590075Sobrien)
984690075Sobrien
984790075Sobrien;; Special patterns for dealing with the constant pool
984890075Sobrien
984990075Sobrien(define_insn "align_4"
985090075Sobrien  [(unspec_volatile [(const_int 0)] VUNSPEC_ALIGN)]
985190075Sobrien  "TARGET_EITHER"
985290075Sobrien  "*
985390075Sobrien  assemble_align (32);
985490075Sobrien  return \"\";
985590075Sobrien  "
985690075Sobrien)
985790075Sobrien
985890075Sobrien(define_insn "align_8"
985990075Sobrien  [(unspec_volatile [(const_int 0)] VUNSPEC_ALIGN8)]
9860132718Skan  "TARGET_REALLY_IWMMXT"
9861132718Skan  "*
9862132718Skan  assemble_align (64);
9863132718Skan  return \"\";
9864132718Skan  "
9865132718Skan)
9866132718Skan
9867132718Skan(define_insn "consttable_end"
9868132718Skan  [(unspec_volatile [(const_int 0)] VUNSPEC_POOL_END)]
986990075Sobrien  "TARGET_EITHER"
987090075Sobrien  "*
987190075Sobrien  making_const_table = FALSE;
987290075Sobrien  return \"\";
987390075Sobrien  "
987490075Sobrien)
987590075Sobrien
987690075Sobrien(define_insn "consttable_1"
987790075Sobrien  [(unspec_volatile [(match_operand 0 "" "")] VUNSPEC_POOL_1)]
987890075Sobrien  "TARGET_THUMB"
987990075Sobrien  "*
988090075Sobrien  making_const_table = TRUE;
988190075Sobrien  assemble_integer (operands[0], 1, BITS_PER_WORD, 1);
988290075Sobrien  assemble_zeros (3);
988390075Sobrien  return \"\";
988490075Sobrien  "
988590075Sobrien  [(set_attr "length" "4")]
988690075Sobrien)
988790075Sobrien
988890075Sobrien(define_insn "consttable_2"
988990075Sobrien  [(unspec_volatile [(match_operand 0 "" "")] VUNSPEC_POOL_2)]
989090075Sobrien  "TARGET_THUMB"
989190075Sobrien  "*
989290075Sobrien  making_const_table = TRUE;
989390075Sobrien  assemble_integer (operands[0], 2, BITS_PER_WORD, 1);
989490075Sobrien  assemble_zeros (2);
989590075Sobrien  return \"\";
989690075Sobrien  "
989790075Sobrien  [(set_attr "length" "4")]
989890075Sobrien)
989990075Sobrien
990090075Sobrien(define_insn "consttable_4"
990190075Sobrien  [(unspec_volatile [(match_operand 0 "" "")] VUNSPEC_POOL_4)]
990290075Sobrien  "TARGET_EITHER"
990390075Sobrien  "*
990490075Sobrien  {
990590075Sobrien    making_const_table = TRUE;
990690075Sobrien    switch (GET_MODE_CLASS (GET_MODE (operands[0])))
990790075Sobrien      {
990890075Sobrien      case MODE_FLOAT:
990990075Sobrien      {
991090075Sobrien        REAL_VALUE_TYPE r;
991190075Sobrien        REAL_VALUE_FROM_CONST_DOUBLE (r, operands[0]);
9912117395Skan        assemble_real (r, GET_MODE (operands[0]), BITS_PER_WORD);
9913117395Skan        break;
9914117395Skan      }
991590075Sobrien      default:
991690075Sobrien        assemble_integer (operands[0], 4, BITS_PER_WORD, 1);
991790075Sobrien        break;
991890075Sobrien      }
991990075Sobrien    return \"\";
992090075Sobrien  }"
992190075Sobrien  [(set_attr "length" "4")]
992290075Sobrien)
992390075Sobrien
992490075Sobrien(define_insn "consttable_8"
992590075Sobrien  [(unspec_volatile [(match_operand 0 "" "")] VUNSPEC_POOL_8)]
992690075Sobrien  "TARGET_EITHER"
992790075Sobrien  "*
992890075Sobrien  {
992990075Sobrien    making_const_table = TRUE;
993090075Sobrien    switch (GET_MODE_CLASS (GET_MODE (operands[0])))
993190075Sobrien      {
993290075Sobrien       case MODE_FLOAT:
993390075Sobrien        {
993490075Sobrien          REAL_VALUE_TYPE r;
993590075Sobrien          REAL_VALUE_FROM_CONST_DOUBLE (r, operands[0]);
9936117395Skan          assemble_real (r, GET_MODE (operands[0]), BITS_PER_WORD);
9937117395Skan          break;
9938117395Skan        }
993990075Sobrien      default:
994090075Sobrien        assemble_integer (operands[0], 8, BITS_PER_WORD, 1);
994190075Sobrien        break;
994290075Sobrien      }
994390075Sobrien    return \"\";
994490075Sobrien  }"
994590075Sobrien  [(set_attr "length" "8")]
994690075Sobrien)
994790075Sobrien
994890075Sobrien;; Miscellaneous Thumb patterns
994990075Sobrien
995090075Sobrien(define_expand "tablejump"
995190075Sobrien  [(parallel [(set (pc) (match_operand:SI 0 "register_operand" ""))
995296263Sobrien	      (use (label_ref (match_operand 1 "" "")))])]
9953132718Skan  "TARGET_THUMB"
995496263Sobrien  "
995596263Sobrien  if (flag_pic)
995696263Sobrien    {
995796263Sobrien      /* Hopefully, CSE will eliminate this copy.  */
995896263Sobrien      rtx reg1 = copy_addr_to_reg (gen_rtx_LABEL_REF (Pmode, operands[1]));
995996263Sobrien      rtx reg2 = gen_reg_rtx (SImode);
996096263Sobrien
996196263Sobrien      emit_insn (gen_addsi3 (reg2, operands[0], reg1));
996296263Sobrien      operands[0] = reg2;
996396263Sobrien    }
996496263Sobrien  "
996596263Sobrien)
996696263Sobrien
996796263Sobrien(define_insn "*thumb_tablejump"
996896263Sobrien  [(set (pc) (match_operand:SI 0 "register_operand" "l*r"))
996996263Sobrien   (use (label_ref (match_operand 1 "" "")))]
997090075Sobrien  "TARGET_THUMB"
997190075Sobrien  "mov\\t%|pc, %0"
997290075Sobrien  [(set_attr "length" "2")]
997396263Sobrien)
997490075Sobrien
997590075Sobrien;; V5 Instructions,
997690075Sobrien
997790075Sobrien(define_insn "clzsi2"
997890075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "=r")
9979132718Skan	(clz:SI (match_operand:SI 1 "s_register_operand" "r")))]
9980132718Skan  "TARGET_ARM && arm_arch5"
9981132718Skan  "clz%?\\t%0, %1"
998290075Sobrien  [(set_attr "predicable" "yes")])
9983132718Skan
9984132718Skan(define_expand "ffssi2"
998590075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
998690075Sobrien	(ffs:SI (match_operand:SI 1 "s_register_operand" "")))]
998790075Sobrien  "TARGET_ARM && arm_arch5"
998890075Sobrien  "
998990075Sobrien  {
999090075Sobrien    rtx t1, t2, t3;
999190075Sobrien
999290075Sobrien    t1 = gen_reg_rtx (SImode);
999390075Sobrien    t2 = gen_reg_rtx (SImode);
999490075Sobrien    t3 = gen_reg_rtx (SImode);
999590075Sobrien
999690075Sobrien    emit_insn (gen_negsi2 (t1, operands[1]));
999790075Sobrien    emit_insn (gen_andsi3 (t2, operands[1], t1));
999890075Sobrien    emit_insn (gen_clzsi2 (t3, t2));
999990075Sobrien    emit_insn (gen_subsi3 (operands[0], GEN_INT (32), t3));
10000132718Skan    DONE;
1000190075Sobrien  }"
1000290075Sobrien)
1000390075Sobrien
1000490075Sobrien(define_expand "ctzsi2"
1000590075Sobrien  [(set (match_operand:SI 0 "s_register_operand" "")
10006132718Skan	(ctz:SI (match_operand:SI 1 "s_register_operand" "")))]
10007132718Skan  "TARGET_ARM && arm_arch5"
10008132718Skan  "
10009132718Skan  {
10010132718Skan    rtx t1, t2, t3;
10011132718Skan
10012132718Skan    t1 = gen_reg_rtx (SImode);
10013132718Skan    t2 = gen_reg_rtx (SImode);
10014132718Skan    t3 = gen_reg_rtx (SImode);
10015132718Skan
10016132718Skan    emit_insn (gen_negsi2 (t1, operands[1]));
10017132718Skan    emit_insn (gen_andsi3 (t2, operands[1], t1));
10018132718Skan    emit_insn (gen_clzsi2 (t3, t2));
10019132718Skan    emit_insn (gen_subsi3 (operands[0], GEN_INT (31), t3));
10020132718Skan    DONE;
10021132718Skan  }"
10022132718Skan)
10023132718Skan
10024132718Skan;; V5E instructions.
10025132718Skan
1002690075Sobrien(define_insn "prefetch"
1002790075Sobrien  [(prefetch (match_operand:SI 0 "address_operand" "p")
1002890075Sobrien	     (match_operand:SI 1 "" "")
1002990075Sobrien	     (match_operand:SI 2 "" ""))]
1003090075Sobrien  "TARGET_ARM && arm_arch5e"
1003190075Sobrien  "pld\\t%a0")
1003290075Sobrien
1003390075Sobrien;; General predication pattern
1003490075Sobrien
1003590075Sobrien(define_cond_exec
1003690075Sobrien  [(match_operator 0 "arm_comparison_operator"
1003790075Sobrien    [(match_operand 1 "cc_register" "")
1003890075Sobrien     (const_int 0)])]
1003990075Sobrien  "TARGET_ARM"
1004090075Sobrien  ""
1004190075Sobrien)
1004290075Sobrien
1004390075Sobrien(define_insn "prologue_use"
1004490075Sobrien  [(unspec:SI [(match_operand:SI 0 "register_operand" "")] UNSPEC_PROLOGUE_USE)]
1004590075Sobrien  ""
1004690075Sobrien  "%@ %0 needed for prologue"
1004790075Sobrien)
1004890075Sobrien
1004990075Sobrien;; Load the FPA co-processor patterns
10050132718Skan(include "fpa.md")
10051132718Skan;; Load the Maverick co-processor patterns
10052132718Skan(include "cirrus.md")
10053132718Skan;; Load the Intel Wireless Multimedia Extension patterns
10054132718Skan(include "iwmmxt.md")
10055132718Skan