summaryrefslogtreecommitdiff
path: root/gcc_arm/config/arm/arm.md
diff options
context:
space:
mode:
Diffstat (limited to 'gcc_arm/config/arm/arm.md')
-rwxr-xr-xgcc_arm/config/arm/arm.md6496
1 files changed, 6496 insertions, 0 deletions
diff --git a/gcc_arm/config/arm/arm.md b/gcc_arm/config/arm/arm.md
new file mode 100755
index 0000000..77f98e3
--- /dev/null
+++ b/gcc_arm/config/arm/arm.md
@@ -0,0 +1,6496 @@
+;;- Machine description for Advanced RISC Machines' ARM for GNU compiler
+;; Copyright (C) 1991, 93-98, 1999, 2002 Free Software Foundation, Inc.
+;; Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl)
+;; and Martin Simmons (@harleqn.co.uk).
+;; More major hacks by Richard Earnshaw (rwe11@cl.cam.ac.uk)
+
+;; This file is part of GNU CC.
+
+;; GNU CC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU CC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU CC; see the file COPYING. If not, write to
+;; the Free Software Foundation, 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
+
+;; There are patterns in this file to support XFmode arithmetic.
+;; Unfortunately RISC iX doesn't work well with these so they are disabled.
+;; (See arm.h)
+
+;; UNSPEC Usage:
+;; 0 `sin' operation: operand 0 is the result, operand 1 the parameter,
+;; the mode is MODE_FLOAT
+;; 1 `cos' operation: operand 0 is the result, operand 1 the parameter,
+;; the mode is MODE_FLOAT
+;; 2 `push multiple' operation: operand 0 is the first register. Subsequent
+;; registers are in parallel (use...) expressions.
+;; 3 A symbol that has been treated properly for pic usage, that is, we
+;; will add the pic_register value to it before trying to dereference it.
+;; Note: sin and cos are no-longer used.
+
+;; Attributes
+
+; PROG_MODE attribute is used to determine whether condition codes are
+; clobbered by a call insn: they are if in prog32 mode. This is controlled
+; by the -mapcs-{32,26} flag, and possibly the -mcpu=... option.
+(define_attr "prog_mode" "prog26,prog32" (const (symbol_ref "arm_prog_mode")))
+
+(define_attr "is_strongarm" "no,yes" (const (symbol_ref "arm_is_strong")))
+
+; Floating Point Unit. If we only have floating point emulation, then there
+; is no point in scheduling the floating point insns. (Well, for best
+; performance we should try and group them together).
+
+(define_attr "fpu" "fpa,fpe2,fpe3" (const (symbol_ref "arm_fpu_attr")))
+
+; LENGTH of an instruction (in bytes)
+(define_attr "length" "" (const_int 4))
+
+; An assembler sequence may clobber the condition codes without us knowing
+(define_asm_attributes
+ [(set_attr "conds" "clob")
+ (set_attr "length" "4")])
+
+; TYPE attribute is used to detect floating point instructions which, if
+; running on a co-processor can run in parallel with other, basic instructions
+; If write-buffer scheduling is enabled then it can also be used in the
+; scheduling of writes.
+
+; Classification of each insn
+; normal any data instruction that doesn't hit memory or fp regs
+; mult a multiply instruction
+; block blockage insn, this blocks all functional units
+; float a floating point arithmetic operation (subject to expansion)
+; fdivx XFmode floating point division
+; fdivd DFmode floating point division
+; fdivs SFmode floating point division
+; fmul Floating point multiply
+; ffmul Fast floating point multiply
+; farith Floating point arithmetic (4 cycle)
+; ffarith Fast floating point arithmetic (2 cycle)
+; float_em a floating point arithmetic operation that is normally emulated
+; even on a machine with an fpa.
+; f_load a floating point load from memory
+; f_store a floating point store to memory
+; f_mem_r a transfer of a floating point register to a real reg via mem
+; r_mem_f the reverse of f_mem_r
+; f_2_r fast transfer float to arm (no memory needed)
+; r_2_f fast transfer arm to float
+; call a subroutine call
+; load any load from memory
+; store1 store 1 word to memory from arm registers
+; store2 store 2 words
+; store3 store 3 words
+; store4 store 4 words
+;
+(define_attr "type"
+ "normal,mult,block,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith,float_em,f_load,f_store,f_mem_r,r_mem_f,f_2_r,r_2_f,call,load,store1,store2,store3,store4"
+ (const_string "normal"))
+
+;; CYGNUS LOCAL load scheduling
+; Load scheduling, set from the arm_ld_sched variable
+; initialised by arm_override_options()
+(define_attr "ldsched" "no,yes"
+ (const (symbol_ref "arm_ld_sched")))
+;; END CYGNUS LOCAL
+
+; condition codes: this one is used by final_prescan_insn to speed up
+; conditionalizing instructions. It saves having to scan the rtl to see if
+; it uses or alters the condition codes.
+
+; USE means that the condition codes are used by the insn in the process of
+; outputting code, this means (at present) that we can't use the insn in
+; inlined branches
+
+; SET means that the purpose of the insn is to set the condition codes in a
+; well defined manner.
+
+; CLOB means that the condition codes are altered in an undefined manner, if
+; they are altered at all
+
+; JUMP_CLOB is used when the conditions are not defined if a branch is taken,
+; but are if the branch wasn't taken; the effect is to limit the branch
+; elimination scanning.
+
+; NOCOND means that the condition codes are neither altered nor affect the
+; output of this insn
+
+(define_attr "conds" "use,set,clob,jump_clob,nocond"
+ (if_then_else (eq_attr "type" "call")
+ (if_then_else (eq_attr "prog_mode" "prog32")
+ (const_string "clob") (const_string "nocond"))
+ (const_string "nocond")))
+
+; Only model the write buffer for ARM6 and ARM7. Earlier processors don't
+; have one. Later ones, such as StrongARM, have write-back caches, so don't
+; suffer blockages enough to warrent modelling this (and it can adversely
+; affect the schedule).
+(define_attr "model_wbuf" "no,yes" (const (symbol_ref "arm_is_6_or_7")))
+
+(define_attr "write_conflict" "no,yes"
+ (if_then_else (eq_attr "type"
+ "block,float_em,f_load,f_store,f_mem_r,r_mem_f,call,load")
+ (const_string "yes")
+ (const_string "no")))
+
+(define_attr "core_cycles" "single,multi"
+ (if_then_else (eq_attr "type"
+ "normal,float,fdivx,fdivd,fdivs,fmul,ffmul,farith,ffarith")
+ (const_string "single")
+ (const_string "multi")))
+
+; The write buffer on some of the arm6 processors is hard to model exactly.
+; There is room in the buffer for up to two addresses and up to eight words
+; of memory, but the two needn't be split evenly. When writing the two
+; addresses are fully pipelined. However, a read from memory that is not
+; currently in the cache will block until the writes have completed.
+; It is normally the case that FCLK and MCLK will be in the ratio 2:1, so
+; writes will take 2 FCLK cycles per word, if FCLK and MCLK are asynchronous
+; (they aren't allowed to be at present) then there is a startup cost of 1MCLK
+; cycle to add as well.
+
+;; (define_function_unit {name} {num-units} {n-users} {test}
+;; {ready-delay} {issue-delay} [{conflict-list}])
+(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa")
+ (eq_attr "type" "fdivx")) 71 69)
+
+(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa")
+ (eq_attr "type" "fdivd")) 59 57)
+
+(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa")
+ (eq_attr "type" "fdivs")) 31 29)
+
+(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa")
+ (eq_attr "type" "fmul")) 9 7)
+
+(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa")
+ (eq_attr "type" "ffmul")) 6 4)
+
+(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa")
+ (eq_attr "type" "farith")) 4 2)
+
+(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa")
+ (eq_attr "type" "ffarith")) 2 2)
+
+(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa")
+ (eq_attr "type" "r_2_f")) 5 3)
+
+(define_function_unit "fpa" 1 0 (and (eq_attr "fpu" "fpa")
+ (eq_attr "type" "f_2_r")) 1 2)
+
+;; The fpa10 doesn't really have a memory read unit, but it can start to
+;; speculatively execute the instruction in the pipeline, provided the data
+;; is already loaded, so pretend reads have a delay of 2 (and that the
+;; pipeline is infinite.
+
+(define_function_unit "fpa_mem" 1 0 (and (eq_attr "fpu" "fpa")
+ (eq_attr "type" "f_load")) 3 1)
+
+;;--------------------------------------------------------------------
+;; Write buffer
+;;--------------------------------------------------------------------
+;; Strictly we should model a 4-deep write buffer for ARM7xx based chips
+(define_function_unit "write_buf" 1 2
+ (and (eq_attr "model_wbuf" "yes")
+ (eq_attr "type" "store1,r_mem_f")) 5 3)
+(define_function_unit "write_buf" 1 2
+ (and (eq_attr "model_wbuf" "yes")
+ (eq_attr "type" "store2")) 7 4)
+(define_function_unit "write_buf" 1 2
+ (and (eq_attr "model_wbuf" "yes")
+ (eq_attr "type" "store3")) 9 5)
+(define_function_unit "write_buf" 1 2
+ (and (eq_attr "model_wbuf" "yes")
+ (eq_attr "type" "store4")) 11 6)
+
+;;--------------------------------------------------------------------
+;; Write blockage unit
+;;--------------------------------------------------------------------
+;; The write_blockage unit models (partially), the fact that reads will stall
+;; until the write buffer empties.
+;; The f_mem_r and r_mem_f could also block, but they are to the stack,
+;; so we don't model them here
+(define_function_unit "write_blockage" 1 0 (and (eq_attr "model_wbuf" "yes")
+ (eq_attr "type" "store1")) 5 5
+ [(eq_attr "write_conflict" "yes")])
+(define_function_unit "write_blockage" 1 0 (and (eq_attr "model_wbuf" "yes")
+ (eq_attr "type" "store2")) 7 7
+ [(eq_attr "write_conflict" "yes")])
+(define_function_unit "write_blockage" 1 0 (and (eq_attr "model_wbuf" "yes")
+ (eq_attr "type" "store3")) 9 9
+ [(eq_attr "write_conflict" "yes")])
+(define_function_unit "write_blockage" 1 0
+ (and (eq_attr "model_wbuf" "yes") (eq_attr "type" "store4")) 11 11
+ [(eq_attr "write_conflict" "yes")])
+(define_function_unit "write_blockage" 1 0
+ (and (eq_attr "model_wbuf" "yes")
+ (eq_attr "write_conflict" "yes")) 1 1)
+
+;;--------------------------------------------------------------------
+;; Core unit
+;;--------------------------------------------------------------------
+;; Everything must spend at least one cycle in the core unit
+(define_function_unit "core" 1 0
+ (and (eq_attr "ldsched" "yes") (eq_attr "type" "store1")) 1 1)
+
+(define_function_unit "core" 1 0
+ (and (eq_attr "ldsched" "yes") (eq_attr "type" "load")) 2 1)
+
+(define_function_unit "core" 1 0
+ (and (eq_attr "ldsched" "!yes") (eq_attr "type" "load,store1")) 2 2)
+
+(define_function_unit "core" 1 0
+ (and (eq_attr "fpu" "fpa") (eq_attr "type" "f_load")) 3 3)
+
+(define_function_unit "core" 1 0
+ (and (eq_attr "fpu" "fpa") (eq_attr "type" "f_store")) 4 4)
+
+(define_function_unit "core" 1 0
+ (and (eq_attr "fpu" "fpa") (eq_attr "type" "r_mem_f")) 6 6)
+
+(define_function_unit "core" 1 0
+ (and (eq_attr "fpu" "fpa") (eq_attr "type" "f_mem_r")) 7 7)
+
+(define_function_unit "core" 1 0
+ (and (eq_attr "ldsched" "no") (eq_attr "type" "mult")) 16 16)
+
+(define_function_unit "core" 1 0
+ (and (and (eq_attr "ldsched" "yes") (eq_attr "is_strongarm" "no"))
+ (eq_attr "type" "mult")) 4 4)
+
+(define_function_unit "core" 1 0
+ (and (and (eq_attr "ldsched" "yes") (eq_attr "is_strongarm" "yes"))
+ (eq_attr "type" "mult")) 3 2)
+
+(define_function_unit "core" 1 0 (eq_attr "type" "store2") 3 3)
+
+(define_function_unit "core" 1 0 (eq_attr "type" "store3") 4 4)
+
+(define_function_unit "core" 1 0 (eq_attr "type" "store4") 5 5)
+
+;; CYGNUS LOCAL
+;; APCS support: When generating code for the software stack checking
+;; model, we need to be able to perform calls to the special exception
+;; handler routines. These routines are *NOT* APCS conforming, so we
+;; do not need to mark any registers as clobbered over the call other
+;; than the lr/r14 modified by the actual BL instruction. Rather than
+;; trying to force the RTL for the existing comparison and call to
+;; achieve this, we simply have a pattern that does the desired job.
+
+;; TODO: This is not ideal since it does not specify all of the
+;; operators involved:
+;; cmp %op0,%op1 cmpsi_insn (compare)
+;; bl%op3 %op2 call_value_symbol (call)
+;; Unfortunately since we do not go through the normal arm_ccfsm_state
+;; processing we cannot use the %? operand replacment for the BL
+;; condition.
+
+(define_insn "cond_call"
+ [(compare:CC (match_operand:SI 0 "s_register_operand" "r")
+ (match_operand:SI 1 "s_register_operand" "r"))
+ (match_operand:SI 2 "" "X")
+ (match_operator 3 "comparison_operator" [(reg:CC 24) (const_int 0)])
+ (clobber (reg:CC 24))
+ (clobber (reg:SI 14))]
+ "GET_CODE (operands[2]) == SYMBOL_REF && GET_CODE (operands[3]) == LTU"
+ "cmp\\t%0, %1\;bllt\\t%a2"
+[(set_attr "conds" "clob")
+ (set_attr "type" "call")
+ (set_attr "length" "8")])
+
+;; END CYGNUS LOCAL
+
+;; Note: For DImode insns, there is normally no reason why operands should
+;; not be in the same register, what we don't want is for something being
+;; written to partially overlap something that is an input.
+
+;; Addition insns.
+
+(define_insn "adddi3"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
+ (plus:DI (match_operand:DI 1 "s_register_operand" "%0,0")
+ (match_operand:DI 2 "s_register_operand" "r,0")))
+ (clobber (reg:CC 24))]
+ ""
+ "adds\\t%Q0, %Q1, %Q2\;adc\\t%R0, %R1, %R2"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8")])
+
+(define_insn "*adddi_sesidi_di"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
+ (plus:DI (sign_extend:DI
+ (match_operand:SI 2 "s_register_operand" "r,r"))
+ (match_operand:DI 1 "s_register_operand" "r,0")))
+ (clobber (reg:CC 24))]
+ ""
+ "adds\\t%Q0, %Q1, %2\;adc\\t%R0, %R1, %2, asr #31"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8")])
+
+(define_insn "*adddi_zesidi_di"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
+ (plus:DI (zero_extend:DI
+ (match_operand:SI 2 "s_register_operand" "r,r"))
+ (match_operand:DI 1 "s_register_operand" "r,0")))
+ (clobber (reg:CC 24))]
+ ""
+ "adds\\t%Q0, %Q1, %2\;adc\\t%R0, %R1, #0"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8")])
+
+(define_expand "addsi3"
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (plus:SI (match_operand:SI 1 "s_register_operand" "")
+ (match_operand:SI 2 "reg_or_int_operand" "")))]
+ ""
+ "
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0],
+ operands[1],
+ (reload_in_progress || reload_completed ? 0
+ : preserve_subexpressions_p ()));
+ DONE;
+ }
+")
+
+(define_split
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (plus:SI (match_operand:SI 1 "s_register_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")))]
+ "! (const_ok_for_arm (INTVAL (operands[2]))
+ || const_ok_for_arm (-INTVAL (operands[2])))"
+ [(clobber (const_int 0))]
+ "
+ arm_split_constant (PLUS, SImode, INTVAL (operands[2]), operands[0],
+ operands[1], 0);
+ DONE;
+")
+
+(define_insn "*addsi3_insn"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
+ (plus:SI (match_operand:SI 1 "s_register_operand" "r,r,r")
+ (match_operand:SI 2 "reg_or_int_operand" "rI,L,?n")))]
+ ""
+ "@
+ add%?\\t%0, %1, %2
+ sub%?\\t%0, %1, #%n2
+ #"
+[(set_attr "length" "4,4,16")])
+
+(define_insn "*addsi3_compare0"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV
+ (plus:SI (match_operand:SI 1 "s_register_operand" "r,r")
+ (match_operand:SI 2 "arm_add_operand" "rI,L"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "@
+ add%?s\\t%0, %1, %2
+ sub%?s\\t%0, %1, #%n2"
+[(set_attr "conds" "set")])
+
+(define_insn "*addsi3_compare0_scratch"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV
+ (plus:SI (match_operand:SI 0 "s_register_operand" "r,r")
+ (match_operand:SI 1 "arm_add_operand" "rI,L"))
+ (const_int 0)))]
+ ""
+ "@
+ cmn%?\\t%0, %1
+ cmp%?\\t%0, #%n1"
+[(set_attr "conds" "set")])
+
+;; The next four insns work because they compare the result with one of
+;; the operands, and we know that the use of the condition code is
+;; either GEU or LTU, so we can use the carry flag from the addition
+;; instead of doing the compare a second time.
+(define_insn "*addsi3_compare_op1"
+ [(set (reg:CC_C 24)
+ (compare:CC_C
+ (plus:SI (match_operand:SI 1 "s_register_operand" "r,r")
+ (match_operand:SI 2 "arm_add_operand" "rI,L"))
+ (match_dup 1)))
+ (set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "@
+ add%?s\\t%0, %1, %2
+ sub%?s\\t%0, %1, #%n2"
+[(set_attr "conds" "set")])
+
+(define_insn "*addsi3_compare_op2"
+ [(set (reg:CC_C 24)
+ (compare:CC_C
+ (plus:SI (match_operand:SI 1 "s_register_operand" "r,r")
+ (match_operand:SI 2 "arm_add_operand" "rI,L"))
+ (match_dup 2)))
+ (set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "@
+ add%?s\\t%0, %1, %2
+ sub%?s\\t%0, %1, #%n2"
+[(set_attr "conds" "set")])
+
+(define_insn "*compare_addsi2_op0"
+ [(set (reg:CC_C 24)
+ (compare:CC_C
+ (plus:SI (match_operand:SI 0 "s_register_operand" "r,r")
+ (match_operand:SI 1 "arm_add_operand" "rI,L"))
+ (match_dup 0)))]
+ ""
+ "@
+ cmn%?\\t%0, %1
+ cmp%?\\t%0, #%n1"
+[(set_attr "conds" "set")])
+
+(define_insn "*compare_addsi2_op1"
+ [(set (reg:CC_C 24)
+ (compare:CC_C
+ (plus:SI (match_operand:SI 0 "s_register_operand" "r,r")
+ (match_operand:SI 1 "arm_add_operand" "rI,L"))
+ (match_dup 1)))]
+ ""
+ "@
+ cmn%?\\t%0, %1
+ cmp%?\\t%0, #%n1"
+[(set_attr "conds" "set")])
+
+(define_insn "*addsi3_carryin"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (plus:SI (ltu:SI (reg:CC_C 24) (const_int 0))
+ (plus:SI (match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "arm_rhs_operand" "rI"))))]
+ ""
+ "adc%?\\t%0, %1, %2"
+[(set_attr "conds" "use")])
+
+(define_insn "*addsi3_carryin_alt1"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (plus:SI (plus:SI (match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "arm_rhs_operand" "rI"))
+ (ltu:SI (reg:CC_C 24) (const_int 0))))]
+ ""
+ "adc%?\\t%0, %1, %2"
+[(set_attr "conds" "use")])
+
+(define_insn "*addsi3_carryin_alt2"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (plus:SI (plus:SI (ltu:SI (reg:CC_C 24) (const_int 0))
+ (match_operand:SI 1 "s_register_operand" "r"))
+ (match_operand:SI 2 "arm_rhs_operand" "rI")))]
+ ""
+ "adc%?\\t%0, %1, %2"
+[(set_attr "conds" "use")])
+
+(define_insn "*addsi3_carryin_alt3"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (plus:SI (plus:SI (ltu:SI (reg:CC_C 24) (const_int 0))
+ (match_operand:SI 2 "arm_rhs_operand" "rI"))
+ (match_operand:SI 1 "s_register_operand" "r")))]
+ ""
+ "adc%?\\t%0, %1, %2"
+[(set_attr "conds" "use")])
+
+(define_insn "incscc"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (plus:SI (match_operator:SI 2 "comparison_operator"
+ [(match_operand 3 "cc_register" "") (const_int 0)])
+ (match_operand:SI 1 "s_register_operand" "0,?r")))]
+ ""
+ "@
+ add%d2\\t%0, %1, #1
+ mov%D2\\t%0, %1\;add%d2\\t%0, %1, #1"
+[(set_attr "conds" "use")
+ (set_attr "length" "4,8")])
+
+; If a constant is too big to fit in a single instruction then the constant
+; will be pre-loaded into a register taking at least two insns, we might be
+; able to merge it with an add, but it depends on the exact value.
+
+(define_split
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (plus:SI (match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "const_int_operand" "n")))]
+ "!(const_ok_for_arm (INTVAL (operands[2]))
+ || const_ok_for_arm (-INTVAL (operands[2])))"
+ [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))
+ (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 3)))]
+ "
+{
+ unsigned int val = (unsigned) INTVAL (operands[2]);
+ int i;
+ unsigned int temp;
+
+ /* this code is similar to the approach followed in movsi, but it must
+ generate exactly two insns */
+
+ for (i = 30; i >= 0; i -= 2)
+ {
+ if (val & (3 << i))
+ {
+ i -= 6;
+ if (i < 0) i = 0;
+ if (const_ok_for_arm (temp = (val & ~(255 << i))))
+ {
+ val &= 255 << i;
+ break;
+ }
+ /* we might be able to do this as (larger number - small number) */
+ temp = ((val >> i) & 255) + 1;
+ if (temp > 255 && i < 24)
+ {
+ i += 2;
+ temp = ((val >> i) & 255) + 1;
+ }
+ if (const_ok_for_arm ((temp << i) - val))
+ {
+ i = temp << i;
+ temp = (unsigned) - (int) (i - val);
+ val = i;
+ break;
+ }
+ FAIL;
+ }
+ }
+ /* if we got here, we have found a way of doing it in two instructions.
+ the two constants are in val and temp */
+ operands[2] = GEN_INT ((int)val);
+ operands[3] = GEN_INT ((int)temp);
+}
+")
+
+(define_insn "addsf3"
+ [(set (match_operand:SF 0 "s_register_operand" "=f,f")
+ (plus:SF (match_operand:SF 1 "s_register_operand" "f,f")
+ (match_operand:SF 2 "fpu_add_operand" "fG,H")))]
+ "TARGET_HARD_FLOAT"
+ "@
+ adf%?s\\t%0, %1, %2
+ suf%?s\\t%0, %1, #%N2"
+[(set_attr "type" "farith")])
+
+(define_insn "adddf3"
+ [(set (match_operand:DF 0 "s_register_operand" "=f,f")
+ (plus:DF (match_operand:DF 1 "s_register_operand" "f,f")
+ (match_operand:DF 2 "fpu_add_operand" "fG,H")))]
+ "TARGET_HARD_FLOAT"
+ "@
+ adf%?d\\t%0, %1, %2
+ suf%?d\\t%0, %1, #%N2"
+[(set_attr "type" "farith")])
+
+(define_insn "*adddf_df_esfdf"
+ [(set (match_operand:DF 0 "s_register_operand" "=f,f")
+ (plus:DF (float_extend:DF
+ (match_operand:SF 1 "s_register_operand" "f,f"))
+ (match_operand:DF 2 "fpu_add_operand" "fG,H")))]
+ "TARGET_HARD_FLOAT"
+ "@
+ adf%?d\\t%0, %1, %2
+ suf%?d\\t%0, %1, #%N2"
+[(set_attr "type" "farith")])
+
+(define_insn "*adddf_df_esfdf"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (plus:DF (match_operand:DF 1 "s_register_operand" "f")
+ (float_extend:DF
+ (match_operand:SF 2 "s_register_operand" "f"))))]
+ "TARGET_HARD_FLOAT"
+ "adf%?d\\t%0, %1, %2"
+[(set_attr "type" "farith")])
+
+(define_insn "*adddf_esfdf_esfdf"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (plus:DF (float_extend:DF
+ (match_operand:SF 1 "s_register_operand" "f"))
+ (float_extend:DF
+ (match_operand:SF 2 "s_register_operand" "f"))))]
+ "TARGET_HARD_FLOAT"
+ "adf%?d\\t%0, %1, %2"
+[(set_attr "type" "farith")])
+
+(define_insn "addxf3"
+ [(set (match_operand:XF 0 "s_register_operand" "=f,f")
+ (plus:XF (match_operand:XF 1 "s_register_operand" "f,f")
+ (match_operand:XF 2 "fpu_add_operand" "fG,H")))]
+ "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT"
+ "@
+ adf%?e\\t%0, %1, %2
+ suf%?e\\t%0, %1, #%N2"
+[(set_attr "type" "farith")])
+
+(define_insn "subdi3"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r,&r")
+ (minus:DI (match_operand:DI 1 "s_register_operand" "0,r,0")
+ (match_operand:DI 2 "s_register_operand" "r,0,0")))
+ (clobber (reg:CC 24))]
+ ""
+ "subs\\t%Q0, %Q1, %Q2\;sbc\\t%R0, %R1, %R2"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8")])
+
+(define_insn "*subdi_di_zesidi"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
+ (minus:DI (match_operand:DI 1 "s_register_operand" "?r,0")
+ (zero_extend:DI
+ (match_operand:SI 2 "s_register_operand" "r,r"))))
+ (clobber (reg:CC 24))]
+ ""
+ "subs\\t%Q0, %Q1, %2\;sbc\\t%R0, %R1, #0"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8")])
+
+(define_insn "*subdi_di_sesidi"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
+ (minus:DI (match_operand:DI 1 "s_register_operand" "r,0")
+ (sign_extend:DI
+ (match_operand:SI 2 "s_register_operand" "r,r"))))
+ (clobber (reg:CC 24))]
+ ""
+ "subs\\t%Q0, %Q1, %2\;sbc\\t%R0, %R1, %2, asr #31"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8")])
+
+(define_insn "*subdi_zesidi_di"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
+ (minus:DI (zero_extend:DI
+ (match_operand:SI 2 "s_register_operand" "r,r"))
+ (match_operand:DI 1 "s_register_operand" "?r,0")))
+ (clobber (reg:CC 24))]
+ ""
+ "rsbs\\t%Q0, %Q1, %2\;rsc\\t%R0, %R1, #0"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8")])
+
+(define_insn "*subdi_sesidi_di"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
+ (minus:DI (sign_extend:DI
+ (match_operand:SI 2 "s_register_operand" "r,r"))
+ (match_operand:DI 1 "s_register_operand" "?r,0")))
+ (clobber (reg:CC 24))]
+ ""
+ "rsbs\\t%Q0, %Q1, %2\;rsc\\t%R0, %R1, %2, asr #31"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8")])
+
+(define_insn "*subdi_zesidi_zesidi"
+ [(set (match_operand:DI 0 "s_register_operand" "=r")
+ (minus:DI (zero_extend:DI
+ (match_operand:SI 1 "s_register_operand" "r"))
+ (zero_extend:DI
+ (match_operand:SI 2 "s_register_operand" "r"))))
+ (clobber (reg:CC 24))]
+ ""
+ "subs\\t%Q0, %1, %2\;rsc\\t%R0, %1, %1"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8")])
+
+(define_expand "subsi3"
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (minus:SI (match_operand:SI 1 "reg_or_int_operand" "")
+ (match_operand:SI 2 "s_register_operand" "")))]
+ ""
+ "
+ if (GET_CODE (operands[1]) == CONST_INT)
+ {
+ arm_split_constant (MINUS, SImode, INTVAL (operands[1]), operands[0],
+ operands[2],
+ (reload_in_progress || reload_completed ? 0
+ : preserve_subexpressions_p ()));
+ DONE;
+ }
+")
+
+(define_insn "*subsi3_insn"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (minus:SI (match_operand:SI 1 "reg_or_int_operand" "rI,?n")
+ (match_operand:SI 2 "s_register_operand" "r,r")))]
+ ""
+ "@
+ rsb%?\\t%0, %2, %1
+ #"
+[(set_attr "length" "4,16")])
+
+(define_split
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (minus:SI (match_operand:SI 1 "const_int_operand" "")
+ (match_operand:SI 2 "s_register_operand" "")))]
+ "! const_ok_for_arm (INTVAL (operands[1]))"
+ [(clobber (const_int 0))]
+ "
+ arm_split_constant (MINUS, SImode, INTVAL (operands[1]), operands[0],
+ operands[2], 0);
+ DONE;
+")
+
+(define_insn "*subsi3_compare0"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV (minus:SI (match_operand:SI 1 "arm_rhs_operand" "r,I")
+ (match_operand:SI 2 "arm_rhs_operand" "rI,r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (minus:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "@
+ sub%?s\\t%0, %1, %2
+ rsb%?s\\t%0, %2, %1"
+[(set_attr "conds" "set")])
+
+(define_insn "decscc"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (minus:SI (match_operand:SI 1 "s_register_operand" "0,?r")
+ (match_operator:SI 2 "comparison_operator"
+ [(match_operand 3 "cc_register" "") (const_int 0)])))]
+ ""
+ "@
+ sub%d2\\t%0, %1, #1
+ mov%D2\\t%0, %1\;sub%d2\\t%0, %1, #1"
+[(set_attr "conds" "use")
+ (set_attr "length" "*,8")])
+
+(define_insn "subsf3"
+ [(set (match_operand:SF 0 "s_register_operand" "=f,f")
+ (minus:SF (match_operand:SF 1 "fpu_rhs_operand" "f,G")
+ (match_operand:SF 2 "fpu_rhs_operand" "fG,f")))]
+ "TARGET_HARD_FLOAT"
+ "@
+ suf%?s\\t%0, %1, %2
+ rsf%?s\\t%0, %2, %1"
+[(set_attr "type" "farith")])
+
+(define_insn "subdf3"
+ [(set (match_operand:DF 0 "s_register_operand" "=f,f")
+ (minus:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G")
+ (match_operand:DF 2 "fpu_rhs_operand" "fG,f")))]
+ "TARGET_HARD_FLOAT"
+ "@
+ suf%?d\\t%0, %1, %2
+ rsf%?d\\t%0, %2, %1"
+[(set_attr "type" "farith")])
+
+(define_insn "*subdf_esfdf_df"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (minus:DF (float_extend:DF
+ (match_operand:SF 1 "s_register_operand" "f"))
+ (match_operand:DF 2 "fpu_rhs_operand" "fG")))]
+ "TARGET_HARD_FLOAT"
+ "suf%?d\\t%0, %1, %2"
+[(set_attr "type" "farith")])
+
+(define_insn "*subdf_df_esfdf"
+ [(set (match_operand:DF 0 "s_register_operand" "=f,f")
+ (minus:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G")
+ (float_extend:DF
+ (match_operand:SF 2 "s_register_operand" "f,f"))))]
+ "TARGET_HARD_FLOAT"
+ "@
+ suf%?d\\t%0, %1, %2
+ rsf%?d\\t%0, %2, %1"
+[(set_attr "type" "farith")])
+
+(define_insn "*subdf_esfdf_esfdf"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (minus:DF (float_extend:DF
+ (match_operand:SF 1 "s_register_operand" "f"))
+ (float_extend:DF
+ (match_operand:SF 2 "s_register_operand" "f"))))]
+ "TARGET_HARD_FLOAT"
+ "suf%?d\\t%0, %1, %2"
+[(set_attr "type" "farith")])
+
+(define_insn "subxf3"
+ [(set (match_operand:XF 0 "s_register_operand" "=f,f")
+ (minus:XF (match_operand:XF 1 "fpu_rhs_operand" "f,G")
+ (match_operand:XF 2 "fpu_rhs_operand" "fG,f")))]
+ "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT"
+ "@
+ suf%?e\\t%0, %1, %2
+ rsf%?e\\t%0, %2, %1"
+[(set_attr "type" "farith")])
+
+;; Multiplication insns
+
+;; Use `&' and then `0' to prevent the operands 0 and 1 being the same
+(define_insn "mulsi3"
+ [(set (match_operand:SI 0 "s_register_operand" "=&r,&r")
+ (mult:SI (match_operand:SI 2 "s_register_operand" "r,r")
+ (match_operand:SI 1 "s_register_operand" "%?r,0")))]
+ ""
+ "mul%?\\t%0, %2, %1"
+[(set_attr "type" "mult")])
+
+(define_insn "*mulsi3_compare0"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV (mult:SI
+ (match_operand:SI 2 "s_register_operand" "r,r")
+ (match_operand:SI 1 "s_register_operand" "%?r,0"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "s_register_operand" "=&r,&r")
+ (mult:SI (match_dup 2) (match_dup 1)))]
+ ""
+ "mul%?s\\t%0, %2, %1"
+[(set_attr "conds" "set")
+ (set_attr "type" "mult")])
+
+(define_insn "*mulsi_compare0_scratch"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV (mult:SI
+ (match_operand:SI 2 "s_register_operand" "r,r")
+ (match_operand:SI 1 "s_register_operand" "%?r,0"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 0 "=&r,&r"))]
+ ""
+ "mul%?s\\t%0, %2, %1"
+[(set_attr "conds" "set")
+ (set_attr "type" "mult")])
+
+;; Unnamed templates to match MLA instruction.
+
+(define_insn "*mulsi3addsi"
+ [(set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r,&r")
+ (plus:SI
+ (mult:SI (match_operand:SI 2 "s_register_operand" "r,r,r,r")
+ (match_operand:SI 1 "s_register_operand" "%r,0,r,0"))
+ (match_operand:SI 3 "s_register_operand" "?r,r,0,0")))]
+ ""
+ "mla%?\\t%0, %2, %1, %3"
+[(set_attr "type" "mult")])
+
+(define_insn "*mulsi3addsi_compare0"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV (plus:SI
+ (mult:SI
+ (match_operand:SI 2 "s_register_operand" "r,r,r,r")
+ (match_operand:SI 1 "s_register_operand" "%r,0,r,0"))
+ (match_operand:SI 3 "s_register_operand" "?r,r,0,0"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r,&r")
+ (plus:SI (mult:SI (match_dup 2) (match_dup 1))
+ (match_dup 3)))]
+ ""
+ "mla%?s\\t%0, %2, %1, %3"
+[(set_attr "conds" "set")
+ (set_attr "type" "mult")])
+
+(define_insn "*mulsi3addsi_compare0_scratch"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV (plus:SI
+ (mult:SI
+ (match_operand:SI 2 "s_register_operand" "r,r,r,r")
+ (match_operand:SI 1 "s_register_operand" "%r,0,r,0"))
+ (match_operand:SI 3 "s_register_operand" "?r,r,0,0"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 0 "=&r,&r,&r,&r"))]
+ ""
+ "mla%?s\\t%0, %2, %1, %3"
+[(set_attr "conds" "set")
+ (set_attr "type" "mult")])
+
+(define_insn "mulsidi3"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r")
+ (mult:DI (sign_extend:DI
+ (match_operand:SI 1 "s_register_operand" "%r"))
+ (sign_extend:DI
+ (match_operand:SI 2 "s_register_operand" "r"))))]
+ "arm_fast_multiply"
+ "smull%?\\t%Q0, %R0, %1, %2"
+[(set_attr "type" "mult")])
+
+(define_insn "umulsidi3"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r")
+ (mult:DI (zero_extend:DI
+ (match_operand:SI 1 "s_register_operand" "%r"))
+ (zero_extend:DI
+ (match_operand:SI 2 "s_register_operand" "r"))))]
+ "arm_fast_multiply"
+ "umull%?\\t%Q0, %R0, %1, %2"
+[(set_attr "type" "mult")])
+
+(define_insn "smulsi3_highpart"
+ [(set (match_operand:SI 0 "s_register_operand" "=&r,&r")
+ (truncate:SI
+ (lshiftrt:DI
+ (mult:DI (sign_extend:DI
+ (match_operand:SI 1 "s_register_operand" "%r,0"))
+ (sign_extend:DI
+ (match_operand:SI 2 "s_register_operand" "r,r")))
+ (const_int 32))))
+ (clobber (match_scratch:SI 3 "=&r,&r"))]
+ "arm_fast_multiply"
+ "smull%?\\t%3, %0, %2, %1"
+[(set_attr "type" "mult")])
+
+(define_insn "umulsi3_highpart"
+ [(set (match_operand:SI 0 "s_register_operand" "=&r,&r")
+ (truncate:SI
+ (lshiftrt:DI
+ (mult:DI (zero_extend:DI
+ (match_operand:SI 1 "s_register_operand" "%r,0"))
+ (zero_extend:DI
+ (match_operand:SI 2 "s_register_operand" "r,r")))
+ (const_int 32))))
+ (clobber (match_scratch:SI 3 "=&r,&r"))]
+ "arm_fast_multiply"
+ "umull%?\\t%3, %0, %2, %1"
+[(set_attr "type" "mult")])
+
+(define_insn "mulsf3"
+ [(set (match_operand:SF 0 "s_register_operand" "=f")
+ (mult:SF (match_operand:SF 1 "s_register_operand" "f")
+ (match_operand:SF 2 "fpu_rhs_operand" "fG")))]
+ "TARGET_HARD_FLOAT"
+ "fml%?s\\t%0, %1, %2"
+[(set_attr "type" "ffmul")])
+
+(define_insn "muldf3"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (mult:DF (match_operand:DF 1 "s_register_operand" "f")
+ (match_operand:DF 2 "fpu_rhs_operand" "fG")))]
+ "TARGET_HARD_FLOAT"
+ "muf%?d\\t%0, %1, %2"
+[(set_attr "type" "fmul")])
+
+(define_insn "*muldf_esfdf_df"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (mult:DF (float_extend:DF
+ (match_operand:SF 1 "s_register_operand" "f"))
+ (match_operand:DF 2 "fpu_rhs_operand" "fG")))]
+ "TARGET_HARD_FLOAT"
+ "muf%?d\\t%0, %1, %2"
+[(set_attr "type" "fmul")])
+
+(define_insn "*muldf_df_esfdf"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (mult:DF (match_operand:DF 1 "s_register_operand" "f")
+ (float_extend:DF
+ (match_operand:SF 2 "s_register_operand" "f"))))]
+ "TARGET_HARD_FLOAT"
+ "muf%?d\\t%0, %1, %2"
+[(set_attr "type" "fmul")])
+
+(define_insn "*muldf_esfdf_esfdf"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (mult:DF (float_extend:DF
+ (match_operand:SF 1 "s_register_operand" "f"))
+ (float_extend:DF
+ (match_operand:SF 2 "s_register_operand" "f"))))]
+ "TARGET_HARD_FLOAT"
+ "muf%?d\\t%0, %1, %2"
+[(set_attr "type" "fmul")])
+
+(define_insn "mulxf3"
+ [(set (match_operand:XF 0 "s_register_operand" "=f")
+ (mult:XF (match_operand:XF 1 "s_register_operand" "f")
+ (match_operand:XF 2 "fpu_rhs_operand" "fG")))]
+ "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT"
+ "muf%?e\\t%0, %1, %2"
+[(set_attr "type" "fmul")])
+
+;; Division insns
+
+(define_insn "divsf3"
+ [(set (match_operand:SF 0 "s_register_operand" "=f,f")
+ (div:SF (match_operand:SF 1 "fpu_rhs_operand" "f,G")
+ (match_operand:SF 2 "fpu_rhs_operand" "fG,f")))]
+ "TARGET_HARD_FLOAT"
+ "@
+ fdv%?s\\t%0, %1, %2
+ frd%?s\\t%0, %2, %1"
+[(set_attr "type" "fdivs")])
+
+(define_insn "divdf3"
+ [(set (match_operand:DF 0 "s_register_operand" "=f,f")
+ (div:DF (match_operand:DF 1 "fpu_rhs_operand" "f,G")
+ (match_operand:DF 2 "fpu_rhs_operand" "fG,f")))]
+ "TARGET_HARD_FLOAT"
+ "@
+ dvf%?d\\t%0, %1, %2
+ rdf%?d\\t%0, %2, %1"
+[(set_attr "type" "fdivd")])
+
+(define_insn "*divdf_esfdf_df"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (div:DF (float_extend:DF
+ (match_operand:SF 1 "s_register_operand" "f"))
+ (match_operand:DF 2 "fpu_rhs_operand" "fG")))]
+ "TARGET_HARD_FLOAT"
+ "dvf%?d\\t%0, %1, %2"
+[(set_attr "type" "fdivd")])
+
+(define_insn "*divdf_df_esfdf"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (div:DF (match_operand:DF 1 "fpu_rhs_operand" "fG")
+ (float_extend:DF
+ (match_operand:SF 2 "s_register_operand" "f"))))]
+ "TARGET_HARD_FLOAT"
+ "rdf%?d\\t%0, %2, %1"
+[(set_attr "type" "fdivd")])
+
+(define_insn "*divdf_esfdf_esfdf"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (div:DF (float_extend:DF
+ (match_operand:SF 1 "s_register_operand" "f"))
+ (float_extend:DF
+ (match_operand:SF 2 "s_register_operand" "f"))))]
+ "TARGET_HARD_FLOAT"
+ "dvf%?d\\t%0, %1, %2"
+[(set_attr "type" "fdivd")])
+
+(define_insn "divxf3"
+ [(set (match_operand:XF 0 "s_register_operand" "=f,f")
+ (div:XF (match_operand:XF 1 "fpu_rhs_operand" "f,G")
+ (match_operand:XF 2 "fpu_rhs_operand" "fG,f")))]
+ "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT"
+ "@
+ dvf%?e\\t%0, %1, %2
+ rdf%?e\\t%0, %2, %1"
+[(set_attr "type" "fdivx")])
+
+;; Modulo insns
+
+(define_insn "modsf3"
+ [(set (match_operand:SF 0 "s_register_operand" "=f")
+ (mod:SF (match_operand:SF 1 "s_register_operand" "f")
+ (match_operand:SF 2 "fpu_rhs_operand" "fG")))]
+ "TARGET_HARD_FLOAT"
+ "rmf%?s\\t%0, %1, %2"
+[(set_attr "type" "fdivs")])
+
+(define_insn "moddf3"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (mod:DF (match_operand:DF 1 "s_register_operand" "f")
+ (match_operand:DF 2 "fpu_rhs_operand" "fG")))]
+ "TARGET_HARD_FLOAT"
+ "rmf%?d\\t%0, %1, %2"
+[(set_attr "type" "fdivd")])
+
+(define_insn "*moddf_esfdf_df"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (mod:DF (float_extend:DF
+ (match_operand:SF 1 "s_register_operand" "f"))
+ (match_operand:DF 2 "fpu_rhs_operand" "fG")))]
+ "TARGET_HARD_FLOAT"
+ "rmf%?d\\t%0, %1, %2"
+[(set_attr "type" "fdivd")])
+
+(define_insn "*moddf_df_esfdf"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (mod:DF (match_operand:DF 1 "s_register_operand" "f")
+ (float_extend:DF
+ (match_operand:SF 2 "s_register_operand" "f"))))]
+ "TARGET_HARD_FLOAT"
+ "rmf%?d\\t%0, %1, %2"
+[(set_attr "type" "fdivd")])
+
+(define_insn "*moddf_esfdf_esfdf"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (mod:DF (float_extend:DF
+ (match_operand:SF 1 "s_register_operand" "f"))
+ (float_extend:DF
+ (match_operand:SF 2 "s_register_operand" "f"))))]
+ "TARGET_HARD_FLOAT"
+ "rmf%?d\\t%0, %1, %2"
+[(set_attr "type" "fdivd")])
+
+(define_insn "modxf3"
+ [(set (match_operand:XF 0 "s_register_operand" "=f")
+ (mod:XF (match_operand:XF 1 "s_register_operand" "f")
+ (match_operand:XF 2 "fpu_rhs_operand" "fG")))]
+ "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT"
+ "rmf%?e\\t%0, %1, %2"
+[(set_attr "type" "fdivx")])
+
+;; Boolean and,ior,xor insns
+
+(define_insn "anddi3"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
+ (and:DI (match_operand:DI 1 "s_register_operand" "%0,0")
+ (match_operand:DI 2 "s_register_operand" "r,0")))]
+ ""
+ "and%?\\t%Q0, %Q1, %Q2\;and%?\\t%R0, %R1, %R2"
+[(set_attr "length" "8")])
+
+(define_insn "*anddi_zesidi_di"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
+ (and:DI (zero_extend:DI
+ (match_operand:SI 2 "s_register_operand" "r,r"))
+ (match_operand:DI 1 "s_register_operand" "?r,0")))]
+ ""
+ "and%?\\t%Q0, %Q1, %2\;mov%?\\t%R0, #0"
+[(set_attr "length" "8")])
+
+(define_insn "*anddi_sesdi_di"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
+ (and:DI (sign_extend:DI
+ (match_operand:SI 2 "s_register_operand" "r,r"))
+ (match_operand:DI 1 "s_register_operand" "?r,0")))]
+ ""
+ "and%?\\t%Q0, %Q1, %2\;and%?\\t%R0, %R1, %2, asr #31"
+[(set_attr "length" "8")])
+
+(define_expand "andsi3"
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (and:SI (match_operand:SI 1 "s_register_operand" "")
+ (match_operand:SI 2 "reg_or_int_operand" "")))]
+ ""
+ "
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ arm_split_constant (AND, SImode, INTVAL (operands[2]), operands[0],
+ operands[1],
+ (reload_in_progress || reload_completed
+ ? 0 : preserve_subexpressions_p ()));
+ DONE;
+ }
+")
+
+(define_insn "*andsi3_insn"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
+ (and:SI (match_operand:SI 1 "s_register_operand" "r,r,r")
+ (match_operand:SI 2 "reg_or_int_operand" "rI,K,?n")))]
+ ""
+ "@
+ and%?\\t%0, %1, %2
+ bic%?\\t%0, %1, #%B2
+ #"
+[(set_attr "length" "4,4,16")])
+
+(define_split
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (and:SI (match_operand:SI 1 "s_register_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")))]
+ "! (const_ok_for_arm (INTVAL (operands[2]))
+ || const_ok_for_arm (~ INTVAL (operands[2])))"
+ [(clobber (const_int 0))]
+ "
+ arm_split_constant (AND, SImode, INTVAL (operands[2]), operands[0],
+ operands[1], 0);
+ DONE;
+")
+
+(define_insn "*andsi3_compare0"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV
+ (and:SI (match_operand:SI 1 "s_register_operand" "r,r")
+ (match_operand:SI 2 "arm_not_operand" "rI,K"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (and:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "@
+ and%?s\\t%0, %1, %2
+ bic%?s\\t%0, %1, #%B2"
+[(set_attr "conds" "set")])
+
+(define_insn "*andsi3_compare0_scratch"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV
+ (and:SI (match_operand:SI 0 "s_register_operand" "r,r")
+ (match_operand:SI 1 "arm_not_operand" "rI,K"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=X,r"))]
+ ""
+ "@
+ tst%?\\t%0, %1
+ bic%?s\\t%3, %0, #%B1"
+[(set_attr "conds" "set")])
+
+(define_insn "*zeroextractsi_compare0_scratch"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV (zero_extract:SI
+ (match_operand:SI 0 "s_register_operand" "r")
+ (match_operand 1 "const_int_operand" "n")
+ (match_operand 2 "const_int_operand" "n"))
+ (const_int 0)))]
+ "INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) < 32
+ && INTVAL (operands[1]) > 0
+ && INTVAL (operands[1]) + (INTVAL (operands[2]) & 1) <= 8
+ && INTVAL (operands[1]) + INTVAL (operands[2]) <= 32"
+ "*
+{
+ unsigned int mask = 0;
+ int cnt = INTVAL (operands[1]);
+
+ while (cnt--)
+ mask = (mask << 1) | 1;
+ operands[1] = GEN_INT (mask << INTVAL (operands[2]));
+ output_asm_insn (\"tst%?\\t%0, %1\", operands);
+ return \"\";
+}
+"
+[(set_attr "conds" "set")])
+
+;; ??? This pattern does not work because it does not check for start+length
+;; less than or equal to 8. This is necessary for the bitfield to fit within
+;; a single byte. This pattern was deleted Feb 25, 1999 in egcs, so we can
+;; just disabled it for 99r1.
+
+(define_insn "*zeroextractqi_compare0_scratch"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV (zero_extract:SI
+ (match_operand:QI 0 "memory_operand" "m")
+ (match_operand 1 "const_int_operand" "n")
+ (match_operand 2 "const_int_operand" "n"))
+ (const_int 0)))
+ (clobber (match_scratch:QI 3 "=r"))]
+ "0 && INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) < 8
+ && INTVAL (operands[1]) > 0 && INTVAL (operands[1]) <= 8"
+ "*
+{
+ unsigned int mask = 0;
+ int cnt = INTVAL (operands[1]);
+
+ while (cnt--)
+ mask = (mask << 1) | 1;
+ operands[1] = GEN_INT (mask << INTVAL (operands[2]));
+ output_asm_insn (\"ldr%?b\\t%3, %0\", operands);
+ output_asm_insn (\"tst%?\\t%3, %1\", operands);
+ return \"\";
+}
+"
+[(set_attr "conds" "set")
+ (set_attr "length" "8")])
+
+;;; ??? This pattern is bogus. If operand3 has bits outside the range
+;;; represented by the bitfield, then this will produce incorrect results.
+;;; Somewhere, the value needs to be truncated. On targets like the m68k,
+;;; which have a real bitfield insert instruction, the truncation happens
+;;; in the bitfield insert instruction itself. Since arm does not have a
+;;; bitfield insert instruction, we would have to emit code here to truncate
+;;; the value before we insert. This loses some of the advantage of having
+;;; this insv pattern, so this pattern needs to be reevalutated.
+
+(define_expand "insv"
+ [(set (zero_extract:SI (match_operand:SI 0 "s_register_operand" "")
+ (match_operand:SI 1 "general_operand" "")
+ (match_operand:SI 2 "general_operand" ""))
+ (match_operand:SI 3 "nonmemory_operand" ""))]
+ ""
+ "
+{
+ int start_bit = INTVAL (operands[2]);
+ int width = INTVAL (operands[1]);
+ HOST_WIDE_INT mask = (((HOST_WIDE_INT)1) << width) - 1;
+ rtx target, subtarget;
+
+ target = operands[0];
+ /* Avoid using a subreg as a subtarget, and avoid writing a paradoxical
+ subreg as the final target. */
+ if (GET_CODE (target) == SUBREG)
+ {
+ subtarget = gen_reg_rtx (SImode);
+ if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (target)))
+ < GET_MODE_SIZE (SImode))
+ target = SUBREG_REG (target);
+ }
+ else
+ subtarget = target;
+
+ if (GET_CODE (operands[3]) == CONST_INT)
+ {
+ /* Since we are inserting a known constant, we may be able to
+ reduce the number of bits that we have to clear so that
+ the mask becomes simple. */
+ /* ??? This code does not check to see if the new mask is actually
+ simpler. It may not be. */
+ rtx op1 = gen_reg_rtx (SImode);
+ /* ??? Truncate operand3 to fit in the bitfield. See comment before
+ start of this pattern. */
+ HOST_WIDE_INT op3_value = mask & INTVAL (operands[3]);
+ HOST_WIDE_INT mask2 = ((mask & ~op3_value) << start_bit);
+
+ emit_insn (gen_andsi3 (op1, operands[0], GEN_INT (~mask2)));
+ emit_insn (gen_iorsi3 (subtarget, op1,
+ GEN_INT (op3_value << start_bit)));
+ }
+ else if (start_bit == 0
+ && ! (const_ok_for_arm (mask)
+ || const_ok_for_arm (~mask)))
+ {
+ /* A Trick, since we are setting the bottom bits in the word,
+ we can shift operand[3] up, operand[0] down, OR them together
+ and rotate the result back again. This takes 3 insns, and
+ the third might be mergable into another op. */
+ /* The shift up copes with the possibility that operand[3] is
+ wider than the bitfield. */
+ rtx op0 = gen_reg_rtx (SImode);
+ rtx op1 = gen_reg_rtx (SImode);
+
+ emit_insn (gen_ashlsi3 (op0, operands[3], GEN_INT (32 - width)));
+ emit_insn (gen_iorsi3 (op1, gen_rtx (LSHIFTRT, SImode, operands[0],
+ operands[1]),
+ op0));
+ emit_insn (gen_rotlsi3 (subtarget, op1, operands[1]));
+ }
+ else if ((width + start_bit == 32)
+ && ! (const_ok_for_arm (mask)
+ || const_ok_for_arm (~mask)))
+ {
+ /* Similar trick, but slightly less efficient. */
+
+ rtx op0 = gen_reg_rtx (SImode);
+ rtx op1 = gen_reg_rtx (SImode);
+
+ emit_insn (gen_ashlsi3 (op0, operands[3], GEN_INT (32 - width)));
+ emit_insn (gen_ashlsi3 (op1, operands[0], operands[1]));
+ emit_insn (gen_iorsi3 (subtarget,
+ gen_rtx (LSHIFTRT, SImode, op1,
+ operands[1]), op0));
+ }
+ else
+ {
+ rtx op0 = GEN_INT (mask);
+ rtx op1 = gen_reg_rtx (SImode);
+ rtx op2 = gen_reg_rtx (SImode);
+
+ if (! (const_ok_for_arm (mask) || const_ok_for_arm (~mask)))
+ {
+ rtx tmp = gen_reg_rtx (SImode);
+
+ emit_insn (gen_movsi (tmp, op0));
+ op0 = tmp;
+ }
+
+ /* Mask out any bits in operand[3] that are not needed. */
+ emit_insn (gen_andsi3 (op1, operands[3], op0));
+
+ if (GET_CODE (op0) == CONST_INT
+ && (const_ok_for_arm (mask << start_bit)
+ || const_ok_for_arm (~ (mask << start_bit))))
+ {
+ op0 = GEN_INT (~(mask << start_bit));
+ emit_insn (gen_andsi3 (op2, operands[0], op0));
+ }
+ else
+ {
+ if (GET_CODE (op0) == CONST_INT)
+ {
+ rtx tmp = gen_reg_rtx (SImode);
+
+ emit_insn (gen_movsi (tmp, op0));
+ op0 = tmp;
+ }
+
+ if (start_bit != 0)
+ op0 = gen_rtx (ASHIFT, SImode, op0, operands[2]);
+
+ emit_insn (gen_andsi_notsi_si (op2, operands[0], op0));
+ }
+
+ if (start_bit != 0)
+ op1 = gen_rtx (ASHIFT, SImode, op1, operands[2]);
+
+ emit_insn (gen_iorsi3 (subtarget, op1, op2));
+ }
+
+ if (subtarget != target)
+ {
+ /* If TARGET is still a SUBREG, then it must be wider than a word,
+ so we must be careful only to set the subword we were asked to. */
+ if (GET_CODE (target) == SUBREG)
+ emit_move_insn (target, subtarget);
+ else
+ emit_move_insn (target, gen_lowpart (GET_MODE (target), subtarget));
+ }
+
+ DONE;
+}
+")
+
+;; constants for op 2 will never be given to these patterns.
+(define_insn "*anddi_notdi_di"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
+ (and:DI (not:DI (match_operand:DI 2 "s_register_operand" "r,0"))
+ (match_operand:DI 1 "s_register_operand" "0,r")))]
+ ""
+ "bic%?\\t%Q0, %Q1, %Q2\;bic%?\\t%R0, %R1, %R2"
+[(set_attr "length" "8")])
+
+(define_insn "*anddi_notzesidi_di"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
+ (and:DI (not:DI (zero_extend:DI
+ (match_operand:SI 2 "s_register_operand" "r,r")))
+ (match_operand:DI 1 "s_register_operand" "0,?r")))]
+ ""
+ "@
+ bic%?\\t%Q0, %Q1, %2
+ bic%?\\t%Q0, %Q1, %2\;mov%?\\t%R0, %R1"
+[(set_attr "length" "4,8")])
+
+(define_insn "*anddi_notsesidi_di"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
+ (and:DI (not:DI (sign_extend:DI
+ (match_operand:SI 2 "s_register_operand" "r,r")))
+ (match_operand:DI 1 "s_register_operand" "?r,0")))]
+ ""
+ "bic%?\\t%Q0, %Q1, %2\;bic%?\\t%R0, %R1, %2, asr #31"
+[(set_attr "length" "8")])
+
+(define_insn "andsi_notsi_si"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (and:SI (not:SI (match_operand:SI 2 "s_register_operand" "r"))
+ (match_operand:SI 1 "s_register_operand" "r")))]
+ ""
+ "bic%?\\t%0, %1, %2")
+
+(define_insn "andsi_not_shiftsi_si"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (and:SI (not:SI (match_operator:SI 4 "shift_operator"
+ [(match_operand:SI 2 "s_register_operand" "r")
+ (match_operand:SI 3 "arm_rhs_operand" "rM")]))
+ (match_operand:SI 1 "s_register_operand" "r")))]
+ ""
+ "bic%?\\t%0, %1, %2%S4")
+
+(define_insn "*andsi_notsi_si_compare0"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV
+ (and:SI (not:SI (match_operand:SI 2 "s_register_operand" "r"))
+ (match_operand:SI 1 "s_register_operand" "r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (and:SI (not:SI (match_dup 2)) (match_dup 1)))]
+ ""
+ "bic%?s\\t%0, %1, %2"
+[(set_attr "conds" "set")])
+
+(define_insn "*andsi_notsi_si_compare0_scratch"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV
+ (and:SI (not:SI (match_operand:SI 2 "s_register_operand" "r"))
+ (match_operand:SI 1 "s_register_operand" "r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 0 "=r"))]
+ ""
+ "bic%?s\\t%0, %1, %2"
+[(set_attr "conds" "set")])
+
+(define_insn "iordi3"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r")
+ (ior:DI (match_operand:DI 1 "s_register_operand" "%0")
+ (match_operand:DI 2 "s_register_operand" "r")))]
+ ""
+ "orr%?\\t%Q0, %Q1, %Q2\;orr%?\\t%R0, %R1, %R2"
+[(set_attr "length" "8")])
+
+(define_insn "*iordi_zesidi_di"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
+ (ior:DI (zero_extend:DI
+ (match_operand:SI 2 "s_register_operand" "r,r"))
+ (match_operand:DI 1 "s_register_operand" "0,?r")))]
+ ""
+ "@
+ orr%?\\t%Q0, %Q1, %2
+ orr%?\\t%Q0, %Q1, %2\;mov%?\\t%R0, %R1"
+[(set_attr "length" "4,8")])
+
+(define_insn "*iordi_sesidi_di"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
+ (ior:DI (sign_extend:DI
+ (match_operand:SI 2 "s_register_operand" "r,r"))
+ (match_operand:DI 1 "s_register_operand" "?r,0")))]
+ ""
+ "orr%?\\t%Q0, %Q1, %2\;orr%?\\t%R0, %R1, %2, asr #31"
+[(set_attr "length" "8")])
+
+(define_expand "iorsi3"
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (ior:SI (match_operand:SI 1 "s_register_operand" "")
+ (match_operand:SI 2 "reg_or_int_operand" "")))]
+ ""
+ "
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ arm_split_constant (IOR, SImode, INTVAL (operands[2]), operands[0],
+ operands[1],
+ (reload_in_progress || reload_completed
+ ? 0 : preserve_subexpressions_p ()));
+ DONE;
+ }
+")
+
+(define_insn "*iorsi3_insn"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (ior:SI (match_operand:SI 1 "s_register_operand" "r,r")
+ (match_operand:SI 2 "reg_or_int_operand" "rI,?n")))]
+ ""
+ "@
+ orr%?\\t%0, %1, %2
+ #"
+[(set_attr "length" "4,16")])
+
+(define_split
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (ior:SI (match_operand:SI 1 "s_register_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")))]
+ "! const_ok_for_arm (INTVAL (operands[2]))"
+ [(clobber (const_int 0))]
+ "
+ arm_split_constant (IOR, SImode, INTVAL (operands[2]), operands[0],
+ operands[1], 0);
+ DONE;
+")
+
+(define_insn "*iorsi3_compare0"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV (ior:SI (match_operand:SI 1 "s_register_operand" "%r")
+ (match_operand:SI 2 "arm_rhs_operand" "rI"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (ior:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "orr%?s\\t%0, %1, %2"
+[(set_attr "conds" "set")])
+
+(define_insn "*iorsi3_compare0_scratch"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV (ior:SI (match_operand:SI 1 "s_register_operand" "%r")
+ (match_operand:SI 2 "arm_rhs_operand" "rI"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 0 "=r"))]
+ ""
+ "orr%?s\\t%0, %1, %2"
+[(set_attr "conds" "set")])
+
+(define_insn "xordi3"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
+ (xor:DI (match_operand:DI 1 "s_register_operand" "%0,0")
+ (match_operand:DI 2 "s_register_operand" "r,0")))]
+ ""
+ "eor%?\\t%Q0, %Q1, %Q2\;eor%?\\t%R0, %R1, %R2"
+[(set_attr "length" "8")])
+
+(define_insn "*xordi_zesidi_di"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
+ (xor:DI (zero_extend:DI
+ (match_operand:SI 2 "s_register_operand" "r,r"))
+ (match_operand:DI 1 "s_register_operand" "0,?r")))]
+ ""
+ "@
+ eor%?\\t%Q0, %Q1, %2
+ eor%?\\t%Q0, %Q1, %2\;mov%?\\t%R0, %R1"
+[(set_attr "length" "4,8")])
+
+(define_insn "*xordi_sesidi_di"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
+ (xor:DI (sign_extend:DI
+ (match_operand:SI 2 "s_register_operand" "r,r"))
+ (match_operand:DI 1 "s_register_operand" "?r,0")))]
+ ""
+ "eor%?\\t%Q0, %Q1, %2\;eor%?\\t%R0, %R1, %2, asr #31"
+[(set_attr "length" "8")])
+
+(define_insn "xorsi3"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (xor:SI (match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "arm_rhs_operand" "rI")))]
+ ""
+ "eor%?\\t%0, %1, %2")
+
+(define_insn "*xorsi3_compare0"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV (xor:SI (match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "arm_rhs_operand" "rI"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (xor:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "eor%?s\\t%0, %1, %2"
+[(set_attr "conds" "set")])
+
+(define_insn "*xorsi3_compare0_scratch"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV (xor:SI (match_operand:SI 0 "s_register_operand" "r")
+ (match_operand:SI 1 "arm_rhs_operand" "rI"))
+ (const_int 0)))]
+ ""
+ "teq%?\\t%0, %1"
+[(set_attr "conds" "set")])
+
+;; by splitting (IOR (AND (NOT A) (NOT B)) C) as D = AND (IOR A B) (NOT C),
+;; (NOT D) we can sometimes merge the final NOT into one of the following
+;; insns
+
+(define_split
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (ior:SI (and:SI (not:SI (match_operand:SI 1 "s_register_operand" "r"))
+ (not:SI (match_operand:SI 2 "arm_rhs_operand" "rI")))
+ (match_operand:SI 3 "arm_rhs_operand" "rI")))
+ (clobber (match_operand:SI 4 "s_register_operand" "=r"))]
+ ""
+ [(set (match_dup 4) (and:SI (ior:SI (match_dup 1) (match_dup 2))
+ (not:SI (match_dup 3))))
+ (set (match_dup 0) (not:SI (match_dup 4)))]
+ ""
+)
+
+(define_insn "*andsi_iorsi3_notsi"
+ [(set (match_operand:SI 0 "s_register_operand" "=&r,&r,&r")
+ (and:SI (ior:SI (match_operand:SI 1 "s_register_operand" "r,r,0")
+ (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI"))
+ (not:SI (match_operand:SI 3 "arm_rhs_operand" "rI,rI,rI"))))]
+ ""
+ "orr%?\\t%0, %1, %2\;bic%?\\t%0, %0, %3"
+[(set_attr "length" "8")])
+
+
+
+;; Minimum and maximum insns
+
+(define_insn "smaxsi3"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
+ (smax:SI (match_operand:SI 1 "s_register_operand" "0,r,?r")
+ (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")))
+ (clobber (reg:CC 24))]
+ ""
+ "@
+ cmp\\t%1, %2\;movlt\\t%0, %2
+ cmp\\t%1, %2\;movge\\t%0, %1
+ cmp\\t%1, %2\;movge\\t%0, %1\;movlt\\t%0, %2"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8,8,12")])
+
+(define_insn "sminsi3"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
+ (smin:SI (match_operand:SI 1 "s_register_operand" "0,r,?r")
+ (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")))
+ (clobber (reg:CC 24))]
+ ""
+ "@
+ cmp\\t%1, %2\;movge\\t%0, %2
+ cmp\\t%1, %2\;movlt\\t%0, %1
+ cmp\\t%1, %2\;movlt\\t%0, %1\;movge\\t%0, %2"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8,8,12")])
+
+(define_insn "umaxsi3"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
+ (umax:SI (match_operand:SI 1 "s_register_operand" "0,r,?r")
+ (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")))
+ (clobber (reg:CC 24))]
+ ""
+ "@
+ cmp\\t%1, %2\;movcc\\t%0, %2
+ cmp\\t%1, %2\;movcs\\t%0, %1
+ cmp\\t%1, %2\;movcs\\t%0, %1\;movcc\\t%0, %2"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8,8,12")])
+
+(define_insn "uminsi3"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
+ (umin:SI (match_operand:SI 1 "s_register_operand" "0,r,?r")
+ (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")))
+ (clobber (reg:CC 24))]
+ ""
+ "@
+ cmp\\t%1, %2\;movcs\\t%0, %2
+ cmp\\t%1, %2\;movcc\\t%0, %1
+ cmp\\t%1, %2\;movcc\\t%0, %1\;movcs\\t%0, %2"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8,8,12")])
+
+(define_insn "*store_minmaxsi"
+ [(set (match_operand:SI 0 "memory_operand" "=m")
+ (match_operator:SI 3 "minmax_operator"
+ [(match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "s_register_operand" "r")]))
+ (clobber (reg:CC 24))]
+ ""
+ "*
+ operands[3] = gen_rtx (minmax_code (operands[3]), SImode, operands[1],
+ operands[2]);
+ output_asm_insn (\"cmp\\t%1, %2\", operands);
+ output_asm_insn (\"str%d3\\t%1, %0\", operands);
+ output_asm_insn (\"str%D3\\t%2, %0\", operands);
+ return \"\";
+"
+[(set_attr "conds" "clob")
+ (set_attr "length" "12")
+ (set_attr "type" "store1")])
+
+; Reject the frame pointer in operand[1], since reloading this after
+; it has been eliminated can cause carnage.
+(define_insn "*minmax_arithsi"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (match_operator:SI 4 "shiftable_operator"
+ [(match_operator:SI 5 "minmax_operator"
+ [(match_operand:SI 2 "s_register_operand" "r,r")
+ (match_operand:SI 3 "arm_rhs_operand" "rI,rI")])
+ (match_operand:SI 1 "s_register_operand" "0,?r")]))
+ (clobber (reg:CC 24))]
+ "GET_CODE (operands[1]) != REG
+ || (REGNO(operands[1]) != FRAME_POINTER_REGNUM
+ && REGNO(operands[1]) != ARG_POINTER_REGNUM)"
+ "*
+{
+ enum rtx_code code = GET_CODE (operands[4]);
+
+ operands[5] = gen_rtx (minmax_code (operands[5]), SImode, operands[2],
+ operands[3]);
+ output_asm_insn (\"cmp\\t%2, %3\", operands);
+ output_asm_insn (\"%i4%d5\\t%0, %1, %2\", operands);
+ if (which_alternative != 0 || operands[3] != const0_rtx
+ || (code != PLUS && code != MINUS && code != IOR && code != XOR))
+ output_asm_insn (\"%i4%D5\\t%0, %1, %3\", operands);
+ return \"\";
+}
+"
+[(set_attr "conds" "clob")
+ (set_attr "length" "12")])
+
+
+;; Shift and rotation insns
+
+(define_expand "ashlsi3"
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (ashift:SI (match_operand:SI 1 "s_register_operand" "")
+ (match_operand:SI 2 "arm_rhs_operand" "")))]
+ ""
+ "
+ if (GET_CODE (operands[2]) == CONST_INT
+ && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31)
+ {
+ emit_insn (gen_movsi (operands[0], const0_rtx));
+ DONE;
+ }
+")
+
+(define_expand "ashrsi3"
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (ashiftrt:SI (match_operand:SI 1 "s_register_operand" "")
+ (match_operand:SI 2 "arm_rhs_operand" "")))]
+ ""
+ "
+ if (GET_CODE (operands[2]) == CONST_INT
+ && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31)
+ operands[2] = GEN_INT (31);
+")
+
+(define_expand "lshrsi3"
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (lshiftrt:SI (match_operand:SI 1 "s_register_operand" "")
+ (match_operand:SI 2 "arm_rhs_operand" "")))]
+ ""
+ "
+ if (GET_CODE (operands[2]) == CONST_INT
+ && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31)
+ {
+ emit_insn (gen_movsi (operands[0], const0_rtx));
+ DONE;
+ }
+")
+
+(define_expand "rotlsi3"
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (rotatert:SI (match_operand:SI 1 "s_register_operand" "")
+ (match_operand:SI 2 "reg_or_int_operand" "")))]
+ ""
+ "
+ if (GET_CODE (operands[2]) == CONST_INT)
+ operands[2] = GEN_INT ((32 - INTVAL (operands[2])) % 32);
+ else
+ {
+ rtx reg = gen_reg_rtx (SImode);
+ emit_insn (gen_subsi3 (reg, GEN_INT (32), operands[2]));
+ operands[2] = reg;
+ }
+")
+
+(define_expand "rotrsi3"
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (rotatert:SI (match_operand:SI 1 "s_register_operand" "")
+ (match_operand:SI 2 "arm_rhs_operand" "")))]
+ ""
+ "
+ if (GET_CODE (operands[2]) == CONST_INT
+ && ((unsigned HOST_WIDE_INT) INTVAL (operands[2])) > 31)
+ operands[2] = GEN_INT (INTVAL (operands[2]) % 32);
+")
+
+(define_insn "*shiftsi3"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (match_operator:SI 3 "shift_operator"
+ [(match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "reg_or_int_operand" "rM")]))]
+ ""
+ "mov%?\\t%0, %1%S3")
+
+(define_insn "*shiftsi3_compare0"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV (match_operator:SI 3 "shift_operator"
+ [(match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "arm_rhs_operand" "rM")])
+ (const_int 0)))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (match_op_dup 3 [(match_dup 1) (match_dup 2)]))]
+ ""
+ "mov%?s\\t%0, %1%S3"
+[(set_attr "conds" "set")])
+
+(define_insn "*shiftsi3_compare0_scratch"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV (match_operator:SI 3 "shift_operator"
+ [(match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "arm_rhs_operand" "rM")])
+ (const_int 0)))
+ (clobber (match_scratch:SI 0 "=r"))]
+ ""
+ "mov%?s\\t%0, %1%S3"
+[(set_attr "conds" "set")])
+
+(define_insn "*notsi_shiftsi"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (not:SI (match_operator:SI 3 "shift_operator"
+ [(match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "arm_rhs_operand" "rM")])))]
+ ""
+ "mvn%?\\t%0, %1%S3")
+
+(define_insn "*notsi_shiftsi_compare0"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV (not:SI (match_operator:SI 3 "shift_operator"
+ [(match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "arm_rhs_operand" "rM")]))
+ (const_int 0)))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (not:SI (match_op_dup 3 [(match_dup 1) (match_dup 2)])))]
+ ""
+ "mvn%?s\\t%0, %1%S3"
+[(set_attr "conds" "set")])
+
+(define_insn "*not_shiftsi_compare0_scratch"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV (not:SI (match_operator:SI 3 "shift_operator"
+ [(match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "arm_rhs_operand" "rM")]))
+ (const_int 0)))
+ (clobber (match_scratch:SI 0 "=r"))]
+ ""
+ "mvn%?s\\t%0, %1%S3"
+[(set_attr "conds" "set")])
+
+
+;; Unary arithmetic insns
+
+(define_insn "negdi2"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
+ (neg:DI (match_operand:DI 1 "s_register_operand" "?r,0")))]
+ ""
+ "rsbs\\t%Q0, %Q1, #0\;rsc\\t%R0, %R1, #0"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8")])
+
+(define_insn "negsi2"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (neg:SI (match_operand:SI 1 "s_register_operand" "r")))]
+ ""
+ "rsb%?\\t%0, %1, #0")
+
+(define_insn "negsf2"
+ [(set (match_operand:SF 0 "s_register_operand" "=f")
+ (neg:SF (match_operand:SF 1 "s_register_operand" "f")))]
+ "TARGET_HARD_FLOAT"
+ "mnf%?s\\t%0, %1"
+[(set_attr "type" "ffarith")])
+
+(define_insn "negdf2"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (neg:DF (match_operand:DF 1 "s_register_operand" "f")))]
+ "TARGET_HARD_FLOAT"
+ "mnf%?d\\t%0, %1"
+[(set_attr "type" "ffarith")])
+
+(define_insn "*negdf_esfdf"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (neg:DF (float_extend:DF
+ (match_operand:SF 1 "s_register_operand" "f"))))]
+ "TARGET_HARD_FLOAT"
+ "mnf%?d\\t%0, %1"
+[(set_attr "type" "ffarith")])
+
+(define_insn "negxf2"
+ [(set (match_operand:XF 0 "s_register_operand" "=f")
+ (neg:XF (match_operand:XF 1 "s_register_operand" "f")))]
+ "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT"
+ "mnf%?e\\t%0, %1"
+[(set_attr "type" "ffarith")])
+
+;; abssi2 doesn't really clobber the condition codes if a different register
+;; is being set. To keep things simple, assume during rtl manipulations that
+;; it does, but tell the final scan operator the truth. Similarly for
+;; (neg (abs...))
+
+(define_insn "abssi2"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,&r")
+ (abs:SI (match_operand:SI 1 "s_register_operand" "0,r")))
+ (clobber (reg:CC 24))]
+ ""
+ "@
+ cmp\\t%0, #0\;rsblt\\t%0, %0, #0
+ eor%?\\t%0, %1, %1, asr #31\;sub%?\\t%0, %0, %1, asr #31"
+[(set_attr "conds" "clob,*")
+ (set_attr "length" "8")])
+
+(define_insn "*neg_abssi2"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,&r")
+ (neg:SI (abs:SI (match_operand:SI 1 "s_register_operand" "0,r"))))
+ (clobber (reg:CC 24))]
+ ""
+ "@
+ cmp\\t%0, #0\;rsbgt\\t%0, %0, #0
+ eor%?\\t%0, %1, %1, asr #31\;rsb%?\\t%0, %0, %1, asr #31"
+[(set_attr "conds" "clob,*")
+ (set_attr "length" "8")])
+
+(define_insn "abssf2"
+ [(set (match_operand:SF 0 "s_register_operand" "=f")
+ (abs:SF (match_operand:SF 1 "s_register_operand" "f")))]
+ "TARGET_HARD_FLOAT"
+ "abs%?s\\t%0, %1"
+[(set_attr "type" "ffarith")])
+
+(define_insn "absdf2"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (abs:DF (match_operand:DF 1 "s_register_operand" "f")))]
+ "TARGET_HARD_FLOAT"
+ "abs%?d\\t%0, %1"
+[(set_attr "type" "ffarith")])
+
+(define_insn "*absdf_esfdf"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (abs:DF (float_extend:DF
+ (match_operand:SF 1 "s_register_operand" "f"))))]
+ "TARGET_HARD_FLOAT"
+ "abs%?d\\t%0, %1"
+[(set_attr "type" "ffarith")])
+
+(define_insn "absxf2"
+ [(set (match_operand:XF 0 "s_register_operand" "=f")
+ (abs:XF (match_operand:XF 1 "s_register_operand" "f")))]
+ "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT"
+ "abs%?e\\t%0, %1"
+[(set_attr "type" "ffarith")])
+
+(define_insn "sqrtsf2"
+ [(set (match_operand:SF 0 "s_register_operand" "=f")
+ (sqrt:SF (match_operand:SF 1 "s_register_operand" "f")))]
+ "TARGET_HARD_FLOAT"
+ "sqt%?s\\t%0, %1"
+[(set_attr "type" "float_em")])
+
+(define_insn "sqrtdf2"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (sqrt:DF (match_operand:DF 1 "s_register_operand" "f")))]
+ "TARGET_HARD_FLOAT"
+ "sqt%?d\\t%0, %1"
+[(set_attr "type" "float_em")])
+
+(define_insn "*sqrtdf_esfdf"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (sqrt:DF (float_extend:DF
+ (match_operand:SF 1 "s_register_operand" "f"))))]
+ "TARGET_HARD_FLOAT"
+ "sqt%?d\\t%0, %1"
+[(set_attr "type" "float_em")])
+
+(define_insn "sqrtxf2"
+ [(set (match_operand:XF 0 "s_register_operand" "=f")
+ (sqrt:XF (match_operand:XF 1 "s_register_operand" "f")))]
+ "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT"
+ "sqt%?e\\t%0, %1"
+[(set_attr "type" "float_em")])
+
+;; SIN COS TAN and family are always emulated, so it's probably better
+;; to always call a library function.
+;(define_insn "sinsf2"
+; [(set (match_operand:SF 0 "s_register_operand" "=f")
+; (unspec:SF [(match_operand:SF 1 "s_register_operand" "f")] 0))]
+; "TARGET_HARD_FLOAT"
+; "sin%?s\\t%0, %1"
+;[(set_attr "type" "float_em")])
+;
+;(define_insn "sindf2"
+; [(set (match_operand:DF 0 "s_register_operand" "=f")
+; (unspec:DF [(match_operand:DF 1 "s_register_operand" "f")] 0))]
+; "TARGET_HARD_FLOAT"
+; "sin%?d\\t%0, %1"
+;[(set_attr "type" "float_em")])
+;
+;(define_insn "*sindf_esfdf"
+; [(set (match_operand:DF 0 "s_register_operand" "=f")
+; (unspec:DF [(float_extend:DF
+; (match_operand:SF 1 "s_register_operand" "f"))] 0))]
+; "TARGET_HARD_FLOAT"
+; "sin%?d\\t%0, %1"
+;[(set_attr "type" "float_em")])
+;
+;(define_insn "sinxf2"
+; [(set (match_operand:XF 0 "s_register_operand" "=f")
+; (unspec:XF [(match_operand:XF 1 "s_register_operand" "f")] 0))]
+; "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT"
+; "sin%?e\\t%0, %1"
+;[(set_attr "type" "float_em")])
+;
+;(define_insn "cossf2"
+; [(set (match_operand:SF 0 "s_register_operand" "=f")
+; (unspec:SF [(match_operand:SF 1 "s_register_operand" "f")] 1))]
+; "TARGET_HARD_FLOAT"
+; "cos%?s\\t%0, %1"
+;[(set_attr "type" "float_em")])
+;
+;(define_insn "cosdf2"
+; [(set (match_operand:DF 0 "s_register_operand" "=f")
+; (unspec:DF [(match_operand:DF 1 "s_register_operand" "f")] 1))]
+; "TARGET_HARD_FLOAT"
+; "cos%?d\\t%0, %1"
+;[(set_attr "type" "float_em")])
+;
+;(define_insn "*cosdf_esfdf"
+; [(set (match_operand:DF 0 "s_register_operand" "=f")
+; (unspec:DF [(float_extend:DF
+; (match_operand:SF 1 "s_register_operand" "f"))] 1))]
+; "TARGET_HARD_FLOAT"
+; "cos%?d\\t%0, %1"
+;[(set_attr "type" "float_em")])
+;
+;(define_insn "cosxf2"
+; [(set (match_operand:XF 0 "s_register_operand" "=f")
+; (unspec:XF [(match_operand:XF 1 "s_register_operand" "f")] 1))]
+; "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT"
+; "cos%?e\\t%0, %1"
+;[(set_attr "type" "float_em")])
+
+(define_insn "one_cmpldi2"
+ [(set (match_operand:DI 0 "s_register_operand" "=&r,&r")
+ (not:DI (match_operand:DI 1 "s_register_operand" "?r,0")))]
+ ""
+ "mvn%?\\t%Q0, %Q1\;mvn%?\\t%R0, %R1"
+[(set_attr "length" "8")])
+
+(define_insn "one_cmplsi2"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (not:SI (match_operand:SI 1 "s_register_operand" "r")))]
+ ""
+ "mvn%?\\t%0, %1")
+
+(define_insn "*notsi_compare0"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV (not:SI (match_operand:SI 1 "s_register_operand" "r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (not:SI (match_dup 1)))]
+ ""
+ "mvn%?s\\t%0, %1"
+[(set_attr "conds" "set")])
+
+(define_insn "*notsi_compare0_scratch"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV (not:SI (match_operand:SI 1 "s_register_operand" "r"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 0 "=r"))]
+ ""
+ "mvn%?s\\t%0, %1"
+[(set_attr "conds" "set")])
+
+;; Fixed <--> Floating conversion insns
+
+(define_insn "floatsisf2"
+ [(set (match_operand:SF 0 "s_register_operand" "=f")
+ (float:SF (match_operand:SI 1 "s_register_operand" "r")))]
+ "TARGET_HARD_FLOAT"
+ "flt%?s\\t%0, %1"
+[(set_attr "type" "r_2_f")])
+
+(define_insn "floatsidf2"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (float:DF (match_operand:SI 1 "s_register_operand" "r")))]
+ "TARGET_HARD_FLOAT"
+ "flt%?d\\t%0, %1"
+[(set_attr "type" "r_2_f")])
+
+(define_insn "floatsixf2"
+ [(set (match_operand:XF 0 "s_register_operand" "=f")
+ (float:XF (match_operand:SI 1 "s_register_operand" "r")))]
+ "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT"
+ "flt%?e\\t%0, %1"
+[(set_attr "type" "r_2_f")])
+
+(define_insn "fix_truncsfsi2"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (fix:SI (match_operand:SF 1 "s_register_operand" "f")))]
+ "TARGET_HARD_FLOAT"
+ "fix%?z\\t%0, %1"
+[(set_attr "type" "f_2_r")])
+
+(define_insn "fix_truncdfsi2"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (fix:SI (match_operand:DF 1 "s_register_operand" "f")))]
+ "TARGET_HARD_FLOAT"
+ "fix%?z\\t%0, %1"
+[(set_attr "type" "f_2_r")])
+
+(define_insn "fix_truncxfsi2"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (fix:SI (match_operand:XF 1 "s_register_operand" "f")))]
+ "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT"
+ "fix%?z\\t%0, %1"
+[(set_attr "type" "f_2_r")])
+
+;; Truncation insns
+
+(define_insn "truncdfsf2"
+ [(set (match_operand:SF 0 "s_register_operand" "=f")
+ (float_truncate:SF
+ (match_operand:DF 1 "s_register_operand" "f")))]
+ "TARGET_HARD_FLOAT"
+ "mvf%?s\\t%0, %1"
+[(set_attr "type" "ffarith")])
+
+(define_insn "truncxfsf2"
+ [(set (match_operand:SF 0 "s_register_operand" "=f")
+ (float_truncate:SF
+ (match_operand:XF 1 "s_register_operand" "f")))]
+ "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT"
+ "mvf%?s\\t%0, %1"
+[(set_attr "type" "ffarith")])
+
+(define_insn "truncxfdf2"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (float_truncate:DF
+ (match_operand:XF 1 "s_register_operand" "f")))]
+ "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT"
+ "mvf%?d\\t%0, %1"
+[(set_attr "type" "ffarith")])
+
+;; Zero and sign extension instructions.
+
+(define_insn "zero_extendsidi2"
+ [(set (match_operand:DI 0 "s_register_operand" "=r")
+ (zero_extend:DI (match_operand:SI 1 "s_register_operand" "r")))]
+ ""
+ "*
+ if (REGNO (operands[1]) != REGNO (operands[0]) + (WORDS_BIG_ENDIAN ? 1 : 0))
+ output_asm_insn (\"mov%?\\t%Q0, %1\", operands);
+ return \"mov%?\\t%R0, #0\";
+"
+[(set_attr "length" "8")])
+
+(define_insn "zero_extendqidi2"
+ [(set (match_operand:DI 0 "s_register_operand" "=r,r")
+ (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
+ ""
+ "@
+ and%?\\t%Q0, %1, #255\;mov%?\\t%R0, #0
+ ldr%?b\\t%Q0, %1\;mov%?\\t%R0, #0"
+[(set_attr "length" "8")
+ (set_attr "type" "*,load")])
+
+(define_insn "extendsidi2"
+ [(set (match_operand:DI 0 "s_register_operand" "=r")
+ (sign_extend:DI (match_operand:SI 1 "s_register_operand" "r")))]
+ ""
+ "*
+ if (REGNO (operands[1]) != REGNO (operands[0]) + (WORDS_BIG_ENDIAN ? 1 : 0))
+ output_asm_insn (\"mov%?\\t%Q0, %1\", operands);
+ return \"mov%?\\t%R0, %Q0, asr #31\";
+"
+[(set_attr "length" "8")])
+
+(define_expand "zero_extendhisi2"
+ [(set (match_dup 2) (ashift:SI (match_operand:HI 1 "nonimmediate_operand" "")
+ (const_int 16)))
+ (set (match_operand:SI 0 "s_register_operand" "")
+ (lshiftrt:SI (match_dup 2) (const_int 16)))]
+ ""
+ "
+{
+ if (arm_arch4 && GET_CODE (operands[1]) == MEM)
+ {
+ /* Note: We do not have to worry about TARGET_SHORT_BY_BYTES
+ here because the insn below will generate an LDRH instruction
+ rather than an LDR instruction, so we cannot get an unaligned
+ word access. */
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+ gen_rtx_ZERO_EXTEND (SImode, operands[1])));
+ DONE;
+ }
+ if (TARGET_SHORT_BY_BYTES && GET_CODE (operands[1]) == MEM)
+ {
+ emit_insn (gen_movhi_bytes (operands[0], operands[1]));
+ DONE;
+ }
+ if (! s_register_operand (operands[1], HImode))
+ operands[1] = copy_to_mode_reg (HImode, operands[1]);
+ operands[1] = gen_lowpart (SImode, operands[1]);
+ operands[2] = gen_reg_rtx (SImode);
+}")
+
+(define_insn "*zero_extendhisi_insn"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
+ "arm_arch4"
+ "ldr%?h\\t%0, %1"
+[(set_attr "type" "load")])
+
+(define_split
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (zero_extend:SI (match_operand:HI 1 "alignable_memory_operand" "")))
+ (clobber (match_operand:SI 2 "s_register_operand" ""))]
+ "! arm_arch4"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_dup 0) (lshiftrt:SI (match_dup 2) (const_int 16)))]
+ "
+{
+ if ((operands[1] = gen_rotated_half_load (operands[1])) == NULL)
+ FAIL;
+}")
+
+(define_split
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (match_operator:SI 3 "shiftable_operator"
+ [(zero_extend:SI (match_operand:HI 1 "alignable_memory_operand" ""))
+ (match_operand:SI 4 "s_register_operand" "")]))
+ (clobber (match_operand:SI 2 "s_register_operand" ""))]
+ "! arm_arch4"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_dup 0)
+ (match_op_dup 3
+ [(lshiftrt:SI (match_dup 2) (const_int 16)) (match_dup 4)]))]
+ "
+{
+ if ((operands[1] = gen_rotated_half_load (operands[1])) == NULL)
+ FAIL;
+}")
+
+(define_expand "zero_extendqisi2"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (zero_extend:SI
+ (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
+ ""
+ "
+ if (GET_CODE (operands[1]) != MEM)
+ {
+ emit_insn (gen_andsi3 (operands[0], gen_lowpart (SImode, operands[1]),
+ GEN_INT (255)));
+ DONE;
+ }
+")
+
+(define_insn "*load_extendqisi"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
+ ""
+ "ldr%?b\\t%0, %1\\t%@ zero_extendqisi2"
+[(set_attr "type" "load")])
+
+(define_split
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (zero_extend:SI (subreg:QI (match_operand:SI 1 "" "") 0)))
+ (clobber (match_operand:SI 2 "s_register_operand" ""))]
+ "GET_CODE (operands[1]) != MEM"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_dup 0) (and:SI (match_dup 2) (const_int 255)))]
+ "")
+
+(define_insn "*compareqi_eq0"
+ [(set (reg:CC_Z 24)
+ (compare:CC_Z (match_operand:QI 0 "s_register_operand" "r")
+ (const_int 0)))]
+ ""
+ "tst\\t%0, #255"
+[(set_attr "conds" "set")])
+
+(define_expand "extendhisi2"
+ [(set (match_dup 2)
+ (ashift:SI (match_operand:HI 1 "nonimmediate_operand" "")
+ (const_int 16)))
+ (set (match_operand:SI 0 "s_register_operand" "")
+ (ashiftrt:SI (match_dup 2)
+ (const_int 16)))]
+ ""
+ "
+{
+ if (arm_arch4 && GET_CODE (operands[1]) == MEM)
+ {
+ /* Note: We do not have to worry about TARGET_SHORT_BY_BYTES
+ here because the insn below will generate an LDRH instruction
+ rather than an LDR instruction, so we cannot get an unaligned
+ word access. */
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+ gen_rtx_SIGN_EXTEND (SImode, operands[1])));
+ DONE;
+ }
+
+ if (TARGET_SHORT_BY_BYTES && GET_CODE (operands[1]) == MEM)
+ {
+ emit_insn (gen_extendhisi2_mem (operands[0], operands[1]));
+ DONE;
+ }
+ if (! s_register_operand (operands[1], HImode))
+ operands[1] = copy_to_mode_reg (HImode, operands[1]);
+ operands[1] = gen_lowpart (SImode, operands[1]);
+ operands[2] = gen_reg_rtx (SImode);
+}")
+
+(define_expand "extendhisi2_mem"
+ [(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" "")))
+ (set (match_dup 3)
+ (zero_extend:SI (match_dup 7)))
+ (set (match_dup 6) (ashift:SI (match_dup 4) (const_int 24)))
+ (set (match_operand:SI 0 "" "")
+ (ior:SI (ashiftrt:SI (match_dup 6) (const_int 16)) (match_dup 5)))]
+ ""
+ "
+{
+ rtx mem1, mem2;
+ rtx addr = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
+
+ mem1 = gen_rtx (MEM, QImode, addr);
+ MEM_COPY_ATTRIBUTES (mem1, operands[1]);
+ RTX_UNCHANGING_P (mem1) = RTX_UNCHANGING_P (operands[1]);
+ mem2 = gen_rtx (MEM, QImode, plus_constant (addr, 1));
+ MEM_COPY_ATTRIBUTES (mem2, operands[1]);
+ RTX_UNCHANGING_P (mem2) = RTX_UNCHANGING_P (operands[1]);
+ operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[1] = mem1;
+ operands[2] = gen_reg_rtx (SImode);
+ operands[3] = gen_reg_rtx (SImode);
+ operands[6] = gen_reg_rtx (SImode);
+ operands[7] = mem2;
+
+ if (BYTES_BIG_ENDIAN)
+ {
+ operands[4] = operands[2];
+ operands[5] = operands[3];
+ }
+ else
+ {
+ operands[4] = operands[3];
+ operands[5] = operands[2];
+ }
+}
+")
+
+(define_insn "*extendhisi_insn"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
+ "arm_arch4"
+ "ldr%?sh\\t%0, %1"
+[(set_attr "type" "load")])
+
+(define_split
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (sign_extend:SI (match_operand:HI 1 "alignable_memory_operand" "")))
+ (clobber (match_operand:SI 2 "s_register_operand" ""))]
+ "! arm_arch4"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_dup 0) (ashiftrt:SI (match_dup 2) (const_int 16)))]
+ "
+{
+ if ((operands[1] = gen_rotated_half_load (operands[1])) == NULL)
+ FAIL;
+}")
+
+(define_split
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (match_operator:SI 3 "shiftable_operator"
+ [(sign_extend:SI (match_operand:HI 1 "alignable_memory_operand" ""))
+ (match_operand:SI 4 "s_register_operand" "")]))
+ (clobber (match_operand:SI 2 "s_register_operand" ""))]
+ "! arm_arch4"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_dup 0)
+ (match_op_dup 3
+ [(ashiftrt:SI (match_dup 2) (const_int 16)) (match_dup 4)]))]
+ "
+{
+ if ((operands[1] = gen_rotated_half_load (operands[1])) == NULL)
+ FAIL;
+}")
+
+(define_expand "extendqihi2"
+ [(set (match_dup 2)
+ (ashift:SI (match_operand:QI 1 "general_operand" "")
+ (const_int 24)))
+ (set (match_operand:HI 0 "s_register_operand" "")
+ (ashiftrt:SI (match_dup 2)
+ (const_int 24)))]
+ ""
+ "
+{
+ if (arm_arch4 && GET_CODE (operands[1]) == MEM)
+ {
+ emit_insn (gen_rtx (SET, VOIDmode, operands[0],
+ gen_rtx (SIGN_EXTEND, HImode, operands[1])));
+ DONE;
+ }
+ if (! s_register_operand (operands[1], QImode))
+ operands[1] = copy_to_mode_reg (QImode, operands[1]);
+ operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[1] = gen_lowpart (SImode, operands[1]);
+ operands[2] = gen_reg_rtx (SImode);
+}")
+
+; Rather than restricting all byte accesses to memory addresses that ldrsb
+; can handle, we fix up the ones that ldrsb can't grok with a split.
+(define_insn "*extendqihi_insn"
+ [(set (match_operand:HI 0 "s_register_operand" "=r")
+ (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))]
+ "arm_arch4"
+ "*
+ /* If the address is invalid, this will split the instruction into two. */
+ if (bad_signed_byte_operand(operands[1], QImode))
+ return \"#\";
+ return \"ldr%?sb\\t%0, %1\";
+"
+[(set_attr "type" "load")
+ (set_attr "length" "8")])
+
+(define_split
+ [(set (match_operand:HI 0 "s_register_operand" "")
+ (sign_extend:HI (match_operand:QI 1 "bad_signed_byte_operand" "")))]
+ "arm_arch4 && reload_completed"
+ [(set (match_dup 3) (match_dup 1))
+ (set (match_dup 0) (sign_extend:HI (match_dup 2)))]
+ "
+ {
+ HOST_WIDE_INT offset;
+
+ operands[3] = gen_rtx (REG, SImode, REGNO (operands[0]));
+ operands[2] = gen_rtx (MEM, QImode, operands[3]);
+ MEM_COPY_ATTRIBUTES (operands[2], operands[1]);
+ RTX_UNCHANGING_P (operands[2]) = RTX_UNCHANGING_P (operands[1]);
+ operands[1] = XEXP (operands[1], 0);
+ if (GET_CODE (operands[1]) == PLUS
+ && GET_CODE (XEXP (operands[1], 1)) == CONST_INT
+ && ! (const_ok_for_arm (offset = INTVAL (XEXP (operands[1], 1)))
+ || const_ok_for_arm (-offset)))
+ {
+ HOST_WIDE_INT low = (offset > 0
+ ? (offset & 0xff) : -((-offset) & 0xff));
+ XEXP (operands[2], 0) = plus_constant (operands[3], low);
+ operands[1] = plus_constant (XEXP (operands[1], 0), offset - low);
+ }
+ /* Ensure the sum is in correct canonical form */
+ else if (GET_CODE (operands[1]) == PLUS
+ && GET_CODE (XEXP (operands[1], 1)) != CONST_INT
+ && ! s_register_operand (XEXP (operands[1], 1), VOIDmode))
+ operands[1] = gen_rtx (PLUS, GET_MODE (operands[1]),
+ XEXP (operands[1], 1), XEXP (operands[1], 0));
+ }
+")
+
+(define_expand "extendqisi2"
+ [(set (match_dup 2)
+ (ashift:SI (match_operand:QI 1 "general_operand" "")
+ (const_int 24)))
+ (set (match_operand:SI 0 "s_register_operand" "")
+ (ashiftrt:SI (match_dup 2)
+ (const_int 24)))]
+ ""
+ "
+{
+ if (arm_arch4 && GET_CODE (operands[1]) == MEM)
+ {
+ emit_insn (gen_rtx (SET, VOIDmode, operands[0],
+ gen_rtx (SIGN_EXTEND, SImode, operands[1])));
+ DONE;
+ }
+ if (! s_register_operand (operands[1], QImode))
+ operands[1] = copy_to_mode_reg (QImode, operands[1]);
+ operands[1] = gen_lowpart (SImode, operands[1]);
+ operands[2] = gen_reg_rtx (SImode);
+}")
+
+; Rather than restricting all byte accesses to memory addresses that ldrsb
+; can handle, we fix up the ones that ldrsb can't grok with a split.
+(define_insn "*extendqisi_insn"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
+ "arm_arch4"
+ "*
+ /* If the address is invalid, this will split the instruction into two. */
+ if (bad_signed_byte_operand(operands[1], QImode))
+ return \"#\";
+ return \"ldr%?sb\\t%0, %1\";
+"
+[(set_attr "type" "load")
+ (set_attr "length" "8")])
+
+(define_split
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (sign_extend:SI (match_operand:QI 1 "bad_signed_byte_operand" "")))]
+ "arm_arch4 && reload_completed"
+ [(set (match_dup 0) (match_dup 1))
+ (set (match_dup 0) (sign_extend:SI (match_dup 2)))]
+ "
+ {
+ HOST_WIDE_INT offset;
+
+ operands[2] = gen_rtx (MEM, QImode, operands[0]);
+ MEM_COPY_ATTRIBUTES (operands[2], operands[1]);
+ RTX_UNCHANGING_P (operands[2]) = RTX_UNCHANGING_P (operands[1]);
+ operands[1] = XEXP (operands[1], 0);
+ if (GET_CODE (operands[1]) == PLUS
+ && GET_CODE (XEXP (operands[1], 1)) == CONST_INT
+ && ! (const_ok_for_arm (offset = INTVAL (XEXP (operands[1], 1)))
+ || const_ok_for_arm (-offset)))
+ {
+ HOST_WIDE_INT low = (offset > 0
+ ? (offset & 0xff) : -((-offset) & 0xff));
+ XEXP (operands[2], 0) = plus_constant (operands[0], low);
+ operands[1] = plus_constant (XEXP (operands[1], 0), offset - low);
+ }
+ /* Ensure the sum is in correct canonical form */
+ else if (GET_CODE (operands[1]) == PLUS
+ && GET_CODE (XEXP (operands[1], 1)) != CONST_INT
+ && ! s_register_operand (XEXP (operands[1], 1), VOIDmode))
+ operands[1] = gen_rtx (PLUS, GET_MODE (operands[1]),
+ XEXP (operands[1], 1), XEXP (operands[1], 0));
+ }
+")
+
+(define_insn "extendsfdf2"
+ [(set (match_operand:DF 0 "s_register_operand" "=f")
+ (float_extend:DF (match_operand:SF 1 "s_register_operand" "f")))]
+ "TARGET_HARD_FLOAT"
+ "mvf%?d\\t%0, %1"
+[(set_attr "type" "ffarith")])
+
+(define_insn "extendsfxf2"
+ [(set (match_operand:XF 0 "s_register_operand" "=f")
+ (float_extend:XF (match_operand:SF 1 "s_register_operand" "f")))]
+ "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT"
+ "mvf%?e\\t%0, %1"
+[(set_attr "type" "ffarith")])
+
+(define_insn "extenddfxf2"
+ [(set (match_operand:XF 0 "s_register_operand" "=f")
+ (float_extend:XF (match_operand:DF 1 "s_register_operand" "f")))]
+ "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT"
+ "mvf%?e\\t%0, %1"
+[(set_attr "type" "ffarith")])
+
+
+;; Move insns (including loads and stores)
+
+;; XXX Just some ideas about movti.
+;; I don't think these are a good idea on the arm, there just aren't enough
+;; registers
+;;(define_expand "loadti"
+;; [(set (match_operand:TI 0 "s_register_operand" "")
+;; (mem:TI (match_operand:SI 1 "address_operand" "")))]
+;; "" "")
+
+;;(define_expand "storeti"
+;; [(set (mem:TI (match_operand:TI 0 "address_operand" ""))
+;; (match_operand:TI 1 "s_register_operand" ""))]
+;; "" "")
+
+;;(define_expand "movti"
+;; [(set (match_operand:TI 0 "general_operand" "")
+;; (match_operand:TI 1 "general_operand" ""))]
+;; ""
+;; "
+;;{
+;; rtx insn;
+;;
+;; if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
+;; operands[1] = copy_to_reg (operands[1]);
+;; if (GET_CODE (operands[0]) == MEM)
+;; insn = gen_storeti (XEXP (operands[0], 0), operands[1]);
+;; else if (GET_CODE (operands[1]) == MEM)
+;; insn = gen_loadti (operands[0], XEXP (operands[1], 0));
+;; else
+;; FAIL;
+;;
+;; emit_insn (insn);
+;; DONE;
+;;}")
+
+;; Recognise garbage generated above.
+
+;;(define_insn ""
+;; [(set (match_operand:TI 0 "general_operand" "=r,r,r,<,>,m")
+;; (match_operand:TI 1 "general_operand" "<,>,m,r,r,r"))]
+;; ""
+;; "*
+;; {
+;; register mem = (which_alternative < 3);
+;; register char *template;
+;;
+;; operands[mem] = XEXP (operands[mem], 0);
+;; switch (which_alternative)
+;; {
+;; case 0: template = \"ldmdb\\t%1!, %M0\"; break;
+;; case 1: template = \"ldmia\\t%1!, %M0\"; break;
+;; case 2: template = \"ldmia\\t%1, %M0\"; break;
+;; case 3: template = \"stmdb\\t%0!, %M1\"; break;
+;; case 4: template = \"stmia\\t%0!, %M1\"; break;
+;; case 5: template = \"stmia\\t%0, %M1\"; break;
+;; }
+;; output_asm_insn (template, operands);
+;; return \"\";
+;; }")
+
+
+(define_insn "movdi"
+ [(set (match_operand:DI 0 "di_operand" "=r,r,o<>")
+ (match_operand:DI 1 "di_operand" "rIK,mi,r"))]
+ ""
+ "*
+ return (output_move_double (operands));
+"
+[(set_attr "length" "8,8,8")
+ (set_attr "type" "*,load,store2")])
+
+(define_expand "movsi"
+ [(set (match_operand:SI 0 "general_operand" "")
+ (match_operand:SI 1 "general_operand" ""))]
+ ""
+ "
+ /* Everything except mem = const or mem = mem can be done easily */
+ if (GET_CODE (operands[0]) == MEM)
+ operands[1] = force_reg (SImode, operands[1]);
+ /* CYGNUS LOCAL nickc */
+ if (! ok_integer_or_other (operands[1]))
+ /* END CYGNUS LOCAL */
+ {
+ arm_split_constant (SET, SImode, INTVAL (operands[1]), operands[0],
+ NULL_RTX,
+ (reload_in_progress || reload_completed ? 0
+ : preserve_subexpressions_p ()));
+ DONE;
+ }
+ if (CONSTANT_P (operands[1]) && flag_pic)
+ operands[1] = legitimize_pic_address (operands[1], SImode,
+ ((reload_in_progress
+ || reload_completed)
+ ? operands[0] : 0));
+")
+
+(define_insn "*movsi_insn"
+ [(set (match_operand:SI 0 "general_operand" "=r,r,r,m")
+ (match_operand:SI 1 "general_operand" "rI,K,mi,r"))]
+ "register_operand (operands[0], SImode)
+ || register_operand (operands[1], SImode)"
+ "@
+ mov%?\\t%0, %1
+ mvn%?\\t%0, #%B1
+ ldr%?\\t%0, %1
+ str%?\\t%1, %0"
+[(set_attr "type" "*,*,load,store1")])
+
+(define_split
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (match_operand:SI 1 "const_int_operand" ""))]
+ "! (const_ok_for_arm (INTVAL (operands[1]))
+ || const_ok_for_arm (~INTVAL (operands[1])))"
+ [(clobber (const_int 0))]
+ "
+ arm_split_constant (SET, SImode, INTVAL (operands[1]), operands[0],
+ NULL_RTX, 0);
+ DONE;
+")
+
+(define_expand "movaddr"
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (match_operand:DI 1 "address_operand" ""))]
+ ""
+ "")
+
+(define_insn "*movaddr_insn"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (match_operand:DI 1 "address_operand" "p"))]
+ "reload_completed
+ && (GET_CODE (operands[1]) == LABEL_REF
+ || (GET_CODE (operands[1]) == CONST
+ && GET_CODE (XEXP (operands[1], 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF
+ && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST_INT))"
+ "adr%?\\t%0, %a1")
+
+/* When generating pic, we need to load the symbol offset into a register.
+ So that the optimizer does not confuse this with a normal symbol load
+ we use an unspec. The offset will be loaded from a constant pool entry,
+ since that is the only type of relocation we can use. */
+
+(define_insn "pic_load_addr"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (unspec:SI [(match_operand 1 "" "")] 3))]
+ "flag_pic"
+ "ldr%?\\t%0, %a1"
+ [(set_attr "type" "load")])
+
+;; This variant is used for AOF assembly, since it needs to mention the
+;; pic register in the rtl.
+(define_expand "pic_load_addr_based"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (unspec:SI [(match_operand 1 "" "") (match_dup 2)] 3))]
+ "flag_pic"
+ "operands[2] = pic_offset_table_rtx;")
+
+(define_insn "*pic_load_addr_based_insn"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (unspec:SI [(match_operand 1 "" "")
+ (match_operand 2 "s_register_operand" "r")] 3))]
+ "flag_pic && operands[2] == pic_offset_table_rtx"
+ "*
+#ifdef AOF_ASSEMBLER
+ operands[1] = aof_pic_entry (operands[1]);
+#endif
+ output_asm_insn (\"ldr%?\\t%0, %a1\", operands);
+ return \"\";
+" [(set_attr "type" "load")])
+
+(define_insn "pic_add_dot_plus_eight"
+ [(set (pc) (label_ref (match_operand 0 "" "")))
+ (set (match_operand 1 "register_operand" "+r")
+ (plus:SI (match_dup 1) (const (plus:SI (pc) (const_int 8)))))]
+ "flag_pic"
+ "add%?\\t%1, %|pc, %1")
+
+;; If copying one reg to another we can set the condition codes according to
+;; its value. Such a move is common after a return from subroutine and the
+;; result is being tested against zero.
+
+(define_insn "*movsi_compare0"
+ [(set (reg:CC 24) (compare:CC (match_operand:SI 1 "s_register_operand" "0,r")
+ (const_int 0)))
+ (set (match_operand:SI 0 "s_register_operand" "=r,r") (match_dup 1))]
+ ""
+ "@
+ cmp%?\\t%0, #0
+ sub%?s\\t%0, %1, #0"
+[(set_attr "conds" "set")])
+
+;; Subroutine to store a half word from a register into memory.
+;; Operand 0 is the source register (HImode)
+;; Operand 1 is the destination address in a register (SImode)
+
+;; In both this routine and the next, we must be careful not to spill
+;; a memory address of reg+large_const into a separate PLUS insn, since this
+;; can generate unrecognizable rtl.
+
+(define_expand "storehi"
+ [;; store the low byte
+ (set (match_operand 1 "" "") (match_dup 3))
+ ;; extract the high byte
+ (set (match_dup 2)
+ (ashiftrt:SI (match_operand 0 "" "") (const_int 8)))
+ ;; store the high byte
+ (set (match_dup 4) (subreg:QI (match_dup 2) 0))] ;explicit subreg safe
+ ""
+ "
+{
+ rtx addr = XEXP (operands[1], 0);
+ enum rtx_code code = GET_CODE (addr);
+
+ if ((code == PLUS && GET_CODE (XEXP (addr, 1)) != CONST_INT)
+ || code == MINUS)
+ addr = force_reg (SImode, addr);
+
+ operands[4] = change_address (operands[1], QImode, plus_constant (addr, 1));
+ operands[1] = change_address (operands[1], QImode, NULL_RTX);
+ operands[3] = gen_lowpart (QImode, operands[0]);
+ operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[2] = gen_reg_rtx (SImode);
+}
+")
+
+(define_expand "storehi_bigend"
+ [(set (match_dup 4) (match_dup 3))
+ (set (match_dup 2)
+ (ashiftrt:SI (match_operand 0 "" "") (const_int 8)))
+ (set (match_operand 1 "" "") (subreg:QI (match_dup 2) 0))]
+ ""
+ "
+{
+ rtx addr = XEXP (operands[1], 0);
+ enum rtx_code code = GET_CODE (addr);
+
+ if ((code == PLUS && GET_CODE (XEXP (addr, 1)) != CONST_INT)
+ || code == MINUS)
+ addr = force_reg (SImode, addr);
+
+ operands[4] = change_address (operands[1], QImode, plus_constant (addr, 1));
+ operands[1] = change_address (operands[1], QImode, NULL_RTX);
+ operands[3] = gen_lowpart (QImode, operands[0]);
+ operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[2] = gen_reg_rtx (SImode);
+}
+")
+
+;; Subroutine to store a half word integer constant into memory.
+(define_expand "storeinthi"
+ [(set (match_operand 0 "" "")
+ (subreg:QI (match_operand 1 "" "") 0))
+ (set (match_dup 3) (subreg:QI (match_dup 2) 0))]
+ ""
+ "
+{
+ HOST_WIDE_INT value = INTVAL (operands[1]);
+ rtx addr = XEXP (operands[0], 0);
+ enum rtx_code code = GET_CODE (addr);
+
+ if ((code == PLUS && GET_CODE (XEXP (addr, 1)) != CONST_INT)
+ || code == MINUS)
+ addr = force_reg (SImode, addr);
+
+ operands[1] = gen_reg_rtx (SImode);
+ if (BYTES_BIG_ENDIAN)
+ {
+ emit_insn (gen_movsi (operands[1], GEN_INT ((value >> 8) & 255)));
+ if ((value & 255) == ((value >> 8) & 255))
+ operands[2] = operands[1];
+ else
+ {
+ operands[2] = gen_reg_rtx (SImode);
+ emit_insn (gen_movsi (operands[2], GEN_INT (value & 255)));
+ }
+ }
+ else
+ {
+ emit_insn (gen_movsi (operands[1], GEN_INT (value & 255)));
+ if ((value & 255) == ((value >> 8) & 255))
+ operands[2] = operands[1];
+ else
+ {
+ operands[2] = gen_reg_rtx (SImode);
+ emit_insn (gen_movsi (operands[2], GEN_INT ((value >> 8) & 255)));
+ }
+ }
+
+ operands[3] = change_address (operands[0], QImode, plus_constant (addr, 1));
+ operands[0] = change_address (operands[0], QImode, NULL_RTX);
+}
+")
+
+(define_expand "storehi_single_op"
+ [(set (match_operand:HI 0 "memory_operand" "")
+ (match_operand:HI 1 "general_operand" ""))]
+ "arm_arch4"
+ "
+ if (! s_register_operand (operands[1], HImode))
+ operands[1] = copy_to_mode_reg (HImode, operands[1]);
+")
+
+(define_expand "movhi"
+ [(set (match_operand:HI 0 "general_operand" "")
+ (match_operand:HI 1 "general_operand" ""))]
+ ""
+ "
+{
+ if (! (reload_in_progress || reload_completed))
+ {
+ if (GET_CODE (operands[0]) == MEM)
+ {
+ if (arm_arch4)
+ {
+ emit_insn (gen_storehi_single_op (operands[0], operands[1]));
+ DONE;
+ }
+ if (GET_CODE (operands[1]) == CONST_INT)
+ emit_insn (gen_storeinthi (operands[0], operands[1]));
+ else
+ {
+ if (GET_CODE (operands[1]) == MEM)
+ operands[1] = force_reg (HImode, operands[1]);
+ if (BYTES_BIG_ENDIAN)
+ emit_insn (gen_storehi_bigend (operands[1], operands[0]));
+ else
+ emit_insn (gen_storehi (operands[1], operands[0]));
+ }
+ DONE;
+ }
+ /* Sign extend a constant, and keep it in an SImode reg. */
+ else if (GET_CODE (operands[1]) == CONST_INT)
+ {
+ rtx reg = gen_reg_rtx (SImode);
+ HOST_WIDE_INT val = INTVAL (operands[1]) & 0xffff;
+
+ /* If the constant is already valid, leave it alone. */
+ if (! const_ok_for_arm (val))
+ {
+ /* If setting all the top bits will make the constant
+ loadable in a single instruction, then set them.
+ Otherwise, sign extend the number. */
+
+ if (const_ok_for_arm (~ (val | ~0xffff)))
+ val |= ~0xffff;
+ else if (val & 0x8000)
+ val |= ~0xffff;
+ }
+
+ emit_insn (gen_movsi (reg, GEN_INT (val)));
+ operands[1] = gen_rtx_SUBREG (HImode, reg, 0);
+ }
+ else if (! arm_arch4)
+ {
+ /* Note: We do not have to worry about TARGET_SHORT_BY_BYTES
+ for v4 and up architectures because LDRH instructions will
+ be used to access the HI values, and these cannot generate
+ unaligned word access faults in the MMU. */
+ if (GET_CODE (operands[1]) == MEM)
+ {
+ if (TARGET_SHORT_BY_BYTES)
+ {
+ rtx base;
+ rtx offset = const0_rtx;
+ rtx reg = gen_reg_rtx (SImode);
+
+ if ((GET_CODE (base = XEXP (operands[1], 0)) == REG
+ || (GET_CODE (base) == PLUS
+ && GET_CODE (offset = XEXP (base, 1)) == CONST_INT
+ && ((INTVAL(offset) & 1) != 1)
+ && GET_CODE (base = XEXP (base, 0)) == REG))
+ && REGNO_POINTER_ALIGN (REGNO (base)) >= 4)
+ {
+ HOST_WIDE_INT new_offset = INTVAL (offset) & ~3;
+ rtx new;
+
+ new = gen_rtx_MEM (SImode,
+ plus_constant (base, new_offset));
+ MEM_COPY_ATTRIBUTES (new, operands[1]);
+ RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (operands[1]);
+ emit_insn (gen_movsi (reg, new));
+ if (((INTVAL (offset) & 2) != 0)
+ ^ (BYTES_BIG_ENDIAN ? 1 : 0))
+ {
+ rtx reg2 = gen_reg_rtx (SImode);
+
+ emit_insn (gen_lshrsi3 (reg2, reg, GEN_INT (16)));
+ reg = reg2;
+ }
+ }
+ else
+ emit_insn (gen_movhi_bytes (reg, operands[1]));
+
+ operands[1] = gen_lowpart (HImode, reg);
+ }
+ else if (BYTES_BIG_ENDIAN)
+ {
+ rtx base;
+ rtx offset = const0_rtx;
+
+ if ((GET_CODE (base = XEXP (operands[1], 0)) == REG
+ || (GET_CODE (base) == PLUS
+ && GET_CODE (offset = XEXP (base, 1)) == CONST_INT
+ && GET_CODE (base = XEXP (base, 0)) == REG))
+ && REGNO_POINTER_ALIGN (REGNO (base)) >= 4)
+ {
+ rtx reg = gen_reg_rtx (SImode);
+ rtx new;
+
+ if ((INTVAL (offset) & 2) == 2)
+ {
+ HOST_WIDE_INT new_offset = INTVAL (offset) ^ 2;
+ new = gen_rtx_MEM (SImode,
+ plus_constant (base, new_offset));
+ MEM_COPY_ATTRIBUTES (new, operands[1]);
+ RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (operands[1]);
+ emit_insn (gen_movsi (reg, new));
+ }
+ else
+ {
+ new = gen_rtx_MEM (SImode, XEXP (operands[1], 0));
+ MEM_COPY_ATTRIBUTES (new, operands[1]);
+ RTX_UNCHANGING_P (new)
+ = RTX_UNCHANGING_P (operands[1]);
+ emit_insn (gen_rotated_loadsi (reg, new));
+ }
+
+ operands[1] = gen_lowpart (HImode, reg);
+ }
+ else
+ {
+ emit_insn (gen_movhi_bigend (operands[0], operands[1]));
+ DONE;
+ }
+ }
+ }
+ }
+ }
+ /* Handle loading a large integer during reload */
+ else if (GET_CODE (operands[1]) == CONST_INT
+ && ! const_ok_for_arm (INTVAL (operands[1]))
+ && ! const_ok_for_arm (~INTVAL (operands[1])))
+ {
+ /* Writing a constant to memory needs a scratch, which should
+ be handled with SECONDARY_RELOADs. */
+ if (GET_CODE (operands[0]) != REG)
+ abort ();
+
+ operands[0] = gen_rtx_SUBREG (SImode, operands[0], 0);
+ emit_insn (gen_movsi (operands[0], operands[1]));
+ DONE;
+ }
+}
+")
+
+(define_insn "rotated_loadsi"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (rotate:SI (match_operand:SI 1 "offsettable_memory_operand" "o")
+ (const_int 16)))]
+ "! TARGET_SHORT_BY_BYTES"
+ "*
+{
+ rtx ops[2];
+
+ ops[0] = operands[0];
+ ops[1] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[1], 0), 2));
+ output_asm_insn (\"ldr%?\\t%0, %1\\t%@ load-rotate\", ops);
+ return \"\";
+}"
+[(set_attr "type" "load")])
+
+(define_expand "movhi_bytes"
+ [(set (match_dup 2) (zero_extend:SI (match_operand:HI 1 "" "")))
+ (set (match_dup 3)
+ (zero_extend:SI (match_dup 6)))
+ (set (match_operand:SI 0 "" "")
+ (ior:SI (ashift:SI (match_dup 4) (const_int 8)) (match_dup 5)))]
+ ""
+ "
+{
+ rtx mem1, mem2;
+ rtx addr = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
+
+ mem1 = gen_rtx (MEM, QImode, addr);
+ MEM_COPY_ATTRIBUTES (mem1, operands[1]);
+ RTX_UNCHANGING_P (mem1) = RTX_UNCHANGING_P (operands[1]);
+ mem2 = gen_rtx (MEM, QImode, plus_constant (addr, 1));
+ MEM_COPY_ATTRIBUTES (mem2, operands[1]);
+ RTX_UNCHANGING_P (mem2) = RTX_UNCHANGING_P (operands[1]);
+ operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[1] = mem1;
+ operands[2] = gen_reg_rtx (SImode);
+ operands[3] = gen_reg_rtx (SImode);
+ operands[6] = mem2;
+
+ if (BYTES_BIG_ENDIAN)
+ {
+ operands[4] = operands[2];
+ operands[5] = operands[3];
+ }
+ else
+ {
+ operands[4] = operands[3];
+ operands[5] = operands[2];
+ }
+}
+")
+
+(define_expand "movhi_bigend"
+ [(set (match_dup 2)
+ (rotate:SI (subreg:SI (match_operand:HI 1 "memory_operand" "") 0)
+ (const_int 16)))
+ (set (match_dup 3)
+ (ashiftrt:SI (match_dup 2) (const_int 16)))
+ (set (match_operand:HI 0 "s_register_operand" "")
+ (subreg:HI (match_dup 3) 0))]
+ ""
+ "
+ operands[2] = gen_reg_rtx (SImode);
+ operands[3] = gen_reg_rtx (SImode);
+")
+
+;; Pattern to recognise insn generated default case above
+;; CYGNUS LOCAL nickc: Store before load to avoid problem with reload.
+(define_insn "*movhi_insn_arch4"
+ [(set (match_operand:HI 0 "general_operand" "=r,r,m,r")
+ (match_operand:HI 1 "general_operand" "rI,K,r,m"))]
+ "arm_arch4
+ && ok_integer_or_other (operands[0])
+ && ok_integer_or_other (operands[1])" ;; CYGNUS LOCAL nickc
+ "@
+ mov%?\\t%0, %1\\t%@ movhi
+ mvn%?\\t%0, #%B1\\t%@ movhi
+ str%?h\\t%1, %0\\t%@ movhi ;; CYGNUS LOCAL nickc
+ ldr%?h\\t%0, %1\\t%@ movhi" ;; CYGNUS LOCAL nickc
+[(set_attr "type" "*,*,store1,load")]) ;; CYGNUS LOCAL nickc
+;; END CYGNUS LOCAL
+
+(define_insn "*movhi_insn_littleend"
+ [(set (match_operand:HI 0 "general_operand" "=r,r,r")
+ (match_operand:HI 1 "general_operand" "rI,K,m"))]
+ "! arm_arch4
+ && ! BYTES_BIG_ENDIAN
+ && ! TARGET_SHORT_BY_BYTES
+ /* CYGNUS LOCAL nickc */
+ && ok_integer_or_other (operands[1])"
+ ;; END CYGNUS LOCAL nickc
+ "@
+ mov%?\\t%0, %1\\t%@ movhi
+ mvn%?\\t%0, #%B1\\t%@ movhi
+ ldr%?\\t%0, %1\\t%@ movhi"
+[(set_attr "type" "*,*,load")])
+
+(define_insn "*movhi_insn_bigend"
+ [(set (match_operand:HI 0 "s_register_operand" "=r,r,r")
+ (match_operand:HI 1 "general_operand" "rI,K,m"))]
+ "! arm_arch4
+ && BYTES_BIG_ENDIAN
+ && ! TARGET_SHORT_BY_BYTES
+ /* CYGNUS LOCAL NICKC */
+ && ok_integer_or_other (operands[1])"
+ ;; END CYGNUS LOCAL
+ "@
+ mov%?\\t%0, %1\\t%@ movhi
+ mvn%?\\t%0, #%B1\\t%@ movhi
+ ldr%?\\t%0, %1\\t%@ movhi_bigend\;mov%?\\t%0, %0, asr #16"
+[(set_attr "type" "*,*,load")
+ (set_attr "length" "4,4,8")])
+
+(define_insn "*loadhi_si_bigend"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (rotate:SI (subreg:SI (match_operand:HI 1 "memory_operand" "m") 0)
+ (const_int 16)))]
+ "BYTES_BIG_ENDIAN
+ && ! TARGET_SHORT_BY_BYTES"
+ "ldr%?\\t%0, %1\\t%@ movhi_bigend"
+[(set_attr "type" "load")])
+
+(define_insn "*movhi_bytes"
+ [(set (match_operand:HI 0 "s_register_operand" "=r,r")
+ (match_operand:HI 1 "arm_rhs_operand" "rI,K"))]
+ "TARGET_SHORT_BY_BYTES"
+ "@
+ mov%?\\t%0, %1\\t%@ movhi
+ mvn%?\\t%0, #%B1\\t%@ movhi")
+
+
+(define_expand "reload_outhi"
+ [(parallel [(match_operand:HI 0 "reload_memory_operand" "=o")
+ (match_operand:HI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "s_register_operand" "=&r")])]
+ ""
+ "
+ arm_reload_out_hi (operands);
+ DONE;
+")
+
+(define_expand "reload_inhi"
+ [(parallel [(match_operand:HI 0 "s_register_operand" "=r")
+ (match_operand:HI 1 "reload_memory_operand" "o")
+ (match_operand:SI 2 "s_register_operand" "=&r")])]
+ "TARGET_SHORT_BY_BYTES"
+ "
+ arm_reload_in_hi (operands);
+ DONE;
+")
+
+(define_expand "movqi"
+ [(set (match_operand:QI 0 "general_operand" "")
+ (match_operand:QI 1 "general_operand" ""))]
+ ""
+ "
+ /* Everything except mem = const or mem = mem can be done easily */
+
+ if (!(reload_in_progress || reload_completed))
+ {
+ if (GET_CODE (operands[1]) == CONST_INT)
+ {
+ rtx reg = gen_reg_rtx (SImode);
+
+ emit_insn (gen_movsi (reg, operands[1]));
+ operands[1] = gen_rtx (SUBREG, QImode, reg, 0);
+ }
+ if (GET_CODE (operands[0]) == MEM)
+ operands[1] = force_reg (QImode, operands[1]);
+ }
+")
+
+
+(define_insn "*movqi_insn"
+ [(set (match_operand:QI 0 "general_operand" "=r,r,r,m")
+ (match_operand:QI 1 "general_operand" "rI,K,m,r"))]
+ "register_operand (operands[0], QImode)
+ || register_operand (operands[1], QImode)"
+ "@
+ mov%?\\t%0, %1
+ mvn%?\\t%0, #%B1
+ ldr%?b\\t%0, %1
+ str%?b\\t%1, %0"
+[(set_attr "type" "*,*,load,store1")])
+
+(define_expand "movsf"
+ [(set (match_operand:SF 0 "general_operand" "")
+ (match_operand:SF 1 "general_operand" ""))]
+ ""
+ "
+ if (GET_CODE (operands[0]) == MEM)
+ operands[1] = force_reg (SFmode, operands[1]);
+")
+
+(define_insn "*movsf_hard_insn"
+ [(set (match_operand:SF 0 "general_operand" "=f,f,f,m,f,r,r,r,m")
+ (match_operand:SF 1 "general_operand" "fG,H,mE,f,r,f,r,mE,r"))]
+ "TARGET_HARD_FLOAT
+ && (GET_CODE (operands[0]) != MEM || register_operand (operands[1], SFmode))"
+ "@
+ mvf%?s\\t%0, %1
+ mnf%?s\\t%0, #%N1
+ ldf%?s\\t%0, %1
+ stf%?s\\t%1, %0
+ str%?\\t%1, [%|sp, #-4]!\;ldf%?s\\t%0, [%|sp], #4
+ stf%?s\\t%1, [%|sp, #-4]!\;ldr%?\\t%0, [%|sp], #4
+ mov%?\\t%0, %1
+ ldr%?\\t%0, %1\\t%@ float
+ str%?\\t%1, %0\\t%@ float"
+[(set_attr "length" "4,4,4,4,8,8,4,4,4")
+ (set_attr "type"
+ "ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r,*,load,store1")])
+
+;; Exactly the same as above, except that all `f' cases are deleted.
+;; This is necessary to prevent reload from ever trying to use a `f' reg
+;; when -msoft-float.
+
+(define_insn "*movsf_soft_insn"
+ [(set (match_operand:SF 0 "general_operand" "=r,r,m")
+ (match_operand:SF 1 "general_operand" "r,mE,r"))]
+ "TARGET_SOFT_FLOAT
+ && (GET_CODE (operands[0]) != MEM || register_operand (operands[1], SFmode))"
+ "@
+ mov%?\\t%0, %1
+ ldr%?\\t%0, %1\\t%@ float
+ str%?\\t%1, %0\\t%@ float"
+[(set_attr "length" "4,4,4")
+ (set_attr "type" "*,load,store1")])
+
+(define_expand "movdf"
+ [(set (match_operand:DF 0 "general_operand" "")
+ (match_operand:DF 1 "general_operand" ""))]
+ ""
+ "
+ if (GET_CODE (operands[0]) == MEM)
+ operands[1] = force_reg (DFmode, operands[1]);
+")
+
+;; Reloading a df mode value stored in integer regs to memory can require a
+;; scratch reg.
+(define_expand "reload_outdf"
+ [(match_operand:DF 0 "reload_memory_operand" "=o")
+ (match_operand:DF 1 "s_register_operand" "r")
+ (match_operand:SI 2 "s_register_operand" "=&r")]
+ ""
+ "
+{
+ enum rtx_code code = GET_CODE (XEXP (operands[0], 0));
+
+ if (code == REG)
+ operands[2] = XEXP (operands[0], 0);
+ else if (code == POST_INC || code == PRE_DEC)
+ {
+ operands[0] = gen_rtx (SUBREG, DImode, operands[0], 0);
+ operands[1] = gen_rtx (SUBREG, DImode, operands[1], 0);
+ emit_insn (gen_movdi (operands[0], operands[1]));
+ DONE;
+ }
+ else if (code == PRE_INC)
+ {
+ rtx reg = XEXP (XEXP (operands[0], 0), 0);
+ emit_insn (gen_addsi3 (reg, reg, GEN_INT (8)));
+ operands[2] = reg;
+ }
+ else if (code == POST_DEC)
+ operands[2] = XEXP (XEXP (operands[0], 0), 0);
+ else
+ emit_insn (gen_addsi3 (operands[2], XEXP (XEXP (operands[0], 0), 0),
+ XEXP (XEXP (operands[0], 0), 1)));
+
+ emit_insn (gen_rtx (SET, VOIDmode, gen_rtx (MEM, DFmode, operands[2]),
+ operands[1]));
+
+ if (code == POST_DEC)
+ emit_insn (gen_addsi3 (operands[2], operands[2], GEN_INT (-8)));
+
+ DONE;
+}
+")
+
+(define_insn "*movdf_hard_insn"
+ [(set (match_operand:DF 0 "general_operand" "=r,Q,r,m,r,f,f,f,m,!f,!r")
+ (match_operand:DF 1 "general_operand" "Q,r,r,r,mF,fG,H,mF,f,r,f"))]
+ "TARGET_HARD_FLOAT
+ && (GET_CODE (operands[0]) != MEM
+ || register_operand (operands[1], DFmode))"
+ "*
+{
+ rtx ops[3];
+
+ switch (which_alternative)
+ {
+ case 0: return \"ldm%?ia\\t%m1, %M0\\t%@ double\";
+ case 1: return \"stm%?ia\\t%m0, %M1\\t%@ double\";
+ case 2: case 3: case 4: return output_move_double (operands);
+ case 5: return \"mvf%?d\\t%0, %1\";
+ case 6: return \"mnf%?d\\t%0, #%N1\";
+ case 7: return \"ldf%?d\\t%0, %1\";
+ case 8: return \"stf%?d\\t%1, %0\";
+ case 9: return output_mov_double_fpu_from_arm (operands);
+ case 10: return output_mov_double_arm_from_fpu (operands);
+ }
+}
+"
+[(set_attr "length" "4,4,8,8,8,4,4,4,4,8,8")
+ (set_attr "type"
+"load,store2,*,store2,load,ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r")])
+
+;; Software floating point version. This is essentially the same as movdi.
+;; Do not use `f' as a constraint to prevent reload from ever trying to use
+;; an `f' reg.
+
+(define_insn "*movdf_soft_insn"
+ [(set (match_operand:DF 0 "soft_df_operand" "=r,r,m")
+ (match_operand:DF 1 "soft_df_operand" "r,mF,r"))]
+ "TARGET_SOFT_FLOAT"
+ "* return output_move_double (operands);"
+[(set_attr "length" "8,8,8")
+ (set_attr "type" "*,load,store2")])
+
+(define_expand "movxf"
+ [(set (match_operand:XF 0 "general_operand" "")
+ (match_operand:XF 1 "general_operand" ""))]
+ "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT"
+ "")
+
+;; Even when the XFmode patterns aren't enabled, we enable this after
+;; reloading so that we can push floating point registers in the prologue.
+
+(define_insn "*movxf_hard_insn"
+ [(set (match_operand:XF 0 "general_operand" "=f,f,f,m,f,r,r")
+ (match_operand:XF 1 "general_operand" "fG,H,m,f,r,f,r"))]
+ "TARGET_HARD_FLOAT && (ENABLE_XF_PATTERNS || reload_completed)"
+ "*
+ switch (which_alternative)
+ {
+ case 0: return \"mvf%?e\\t%0, %1\";
+ case 1: return \"mnf%?e\\t%0, #%N1\";
+ case 2: return \"ldf%?e\\t%0, %1\";
+ case 3: return \"stf%?e\\t%1, %0\";
+ case 4: return output_mov_long_double_fpu_from_arm (operands);
+ case 5: return output_mov_long_double_arm_from_fpu (operands);
+ case 6: return output_mov_long_double_arm_from_arm (operands);
+ }
+"
+[(set_attr "length" "4,4,4,4,8,8,12")
+ (set_attr "type" "ffarith,ffarith,f_load,f_store,r_mem_f,f_mem_r,*")])
+
+
+;; load- and store-multiple insns
+;; The arm can load/store any set of registers, provided that they are in
+;; ascending order; but that is beyond GCC so stick with what it knows.
+
+(define_expand "load_multiple"
+ [(match_par_dup 3 [(set (match_operand:SI 0 "" "")
+ (match_operand:SI 1 "" ""))
+ (use (match_operand:SI 2 "" ""))])]
+ ""
+ "
+ /* Support only fixed point registers */
+ if (GET_CODE (operands[2]) != CONST_INT
+ || INTVAL (operands[2]) > 14
+ || INTVAL (operands[2]) < 2
+ || GET_CODE (operands[1]) != MEM
+ || GET_CODE (operands[0]) != REG
+ || REGNO (operands[0]) > 14
+ || REGNO (operands[0]) + INTVAL (operands[2]) > 15)
+ FAIL;
+
+ operands[3]
+ = arm_gen_load_multiple (REGNO (operands[0]), INTVAL (operands[2]),
+ force_reg (SImode, XEXP (operands[1], 0)),
+ TRUE, FALSE, RTX_UNCHANGING_P(operands[1]),
+ MEM_IN_STRUCT_P(operands[1]),
+ MEM_SCALAR_P (operands[1]));
+")
+
+;; Load multiple with write-back
+
+(define_insn "*ldmsi_postinc"
+ [(match_parallel 0 "load_multiple_operation"
+ [(set (match_operand:SI 1 "s_register_operand" "+r")
+ (plus:SI (match_dup 1)
+ (match_operand:SI 2 "const_int_operand" "n")))
+ (set (match_operand:SI 3 "s_register_operand" "=r")
+ (mem:SI (match_dup 1)))])]
+ "(INTVAL (operands[2]) == 4 * (XVECLEN (operands[0], 0) - 2))"
+ "*
+{
+ rtx ops[3];
+ int count = XVECLEN (operands[0], 0);
+
+ ops[0] = XEXP (SET_SRC (XVECEXP (operands[0], 0, 0)), 0);
+ ops[1] = SET_DEST (XVECEXP (operands[0], 0, 1));
+ ops[2] = SET_DEST (XVECEXP (operands[0], 0, count - 2));
+
+ output_asm_insn (\"ldm%?ia\\t%0!, {%1-%2}\\t%@ load multiple\", ops);
+ return \"\";
+}
+"
+[(set_attr "type" "load")])
+
+;; Ordinary load multiple
+
+(define_insn "*ldmsi"
+ [(match_parallel 0 "load_multiple_operation"
+ [(set (match_operand:SI 1 "s_register_operand" "=r")
+ (mem:SI (match_operand:SI 2 "s_register_operand" "r")))])]
+ ""
+ "*
+{
+ rtx ops[3];
+ int count = XVECLEN (operands[0], 0);
+
+ ops[0] = XEXP (SET_SRC (XVECEXP (operands[0], 0, 0)), 0);
+ ops[1] = SET_DEST (XVECEXP (operands[0], 0, 0));
+ ops[2] = SET_DEST (XVECEXP (operands[0], 0, count - 1));
+
+ output_asm_insn (\"ldm%?ia\\t%0, {%1-%2}\\t%@ load multiple\", ops);
+ return \"\";
+}
+"
+[(set_attr "type" "load")])
+
+(define_expand "store_multiple"
+ [(match_par_dup 3 [(set (match_operand:SI 0 "" "")
+ (match_operand:SI 1 "" ""))
+ (use (match_operand:SI 2 "" ""))])]
+ ""
+ "
+ /* Support only fixed point registers */
+ if (GET_CODE (operands[2]) != CONST_INT
+ || INTVAL (operands[2]) > 14
+ || INTVAL (operands[2]) < 2
+ || GET_CODE (operands[1]) != REG
+ || GET_CODE (operands[0]) != MEM
+ || REGNO (operands[1]) > 14
+ || REGNO (operands[1]) + INTVAL (operands[2]) > 15)
+ FAIL;
+
+ operands[3]
+ = arm_gen_store_multiple (REGNO (operands[1]), INTVAL (operands[2]),
+ force_reg (SImode, XEXP (operands[0], 0)),
+ TRUE, FALSE, RTX_UNCHANGING_P (operands[0]),
+ MEM_IN_STRUCT_P(operands[0]),
+ MEM_SCALAR_P (operands[0]));
+")
+
+;; Store multiple with write-back
+
+(define_insn "*stmsi_postinc"
+ [(match_parallel 0 "store_multiple_operation"
+ [(set (match_operand:SI 1 "s_register_operand" "+r")
+ (plus:SI (match_dup 1)
+ (match_operand:SI 2 "const_int_operand" "n")))
+ (set (mem:SI (match_dup 1))
+ (match_operand:SI 3 "s_register_operand" "r"))])]
+ "(INTVAL (operands[2]) == 4 * (XVECLEN (operands[0], 0) - 2))"
+ "*
+{
+ rtx ops[3];
+ int count = XVECLEN (operands[0], 0);
+
+ ops[0] = XEXP (SET_SRC (XVECEXP (operands[0], 0, 0)), 0);
+ ops[1] = SET_SRC (XVECEXP (operands[0], 0, 1));
+ ops[2] = SET_SRC (XVECEXP (operands[0], 0, count - 2));
+
+ output_asm_insn (\"stm%?ia\\t%0!, {%1-%2}\\t%@ str multiple\", ops);
+ return \"\";
+}
+"
+[(set (attr "type")
+ (cond [(eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 4))
+ (const_string "store2")
+ (eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 5))
+ (const_string "store3")]
+ (const_string "store4")))])
+
+;; Ordinary store multiple
+
+(define_insn "*stmsi"
+ [(match_parallel 0 "store_multiple_operation"
+ [(set (mem:SI (match_operand:SI 2 "s_register_operand" "r"))
+ (match_operand:SI 1 "s_register_operand" "r"))])]
+ ""
+ "*
+{
+ rtx ops[3];
+ int count = XVECLEN (operands[0], 0);
+
+ ops[0] = XEXP (SET_DEST (XVECEXP (operands[0], 0, 0)), 0);
+ ops[1] = SET_SRC (XVECEXP (operands[0], 0, 0));
+ ops[2] = SET_SRC (XVECEXP (operands[0], 0, count - 1));
+
+ output_asm_insn (\"stm%?ia\\t%0, {%1-%2}\\t%@ str multiple\", ops);
+ return \"\";
+}
+"
+[(set (attr "type")
+ (cond [(eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 3))
+ (const_string "store2")
+ (eq (symbol_ref "XVECLEN (operands[0],0)") (const_int 4))
+ (const_string "store3")]
+ (const_string "store4")))])
+
+;; Move a block of memory if it is word aligned and MORE than 2 words long.
+;; We could let this apply for blocks of less than this, but it clobbers so
+;; many registers that there is then probably a better way.
+
+(define_expand "movstrqi"
+ [(match_operand:BLK 0 "general_operand" "")
+ (match_operand:BLK 1 "general_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")
+ (match_operand:SI 3 "const_int_operand" "")]
+ ""
+ "
+ if (arm_gen_movstrqi (operands))
+ DONE;
+ FAIL;
+")
+
+
+;; Comparison and test insns
+
+(define_expand "cmpsi"
+ [(match_operand:SI 0 "s_register_operand" "")
+ (match_operand:SI 1 "arm_add_operand" "")]
+ ""
+ "
+{
+ arm_compare_op0 = operands[0];
+ arm_compare_op1 = operands[1];
+ arm_compare_fp = 0;
+ DONE;
+}
+")
+
+(define_expand "cmpsf"
+ [(match_operand:SF 0 "s_register_operand" "")
+ (match_operand:SF 1 "fpu_rhs_operand" "")]
+ "TARGET_HARD_FLOAT"
+ "
+{
+ arm_compare_op0 = operands[0];
+ arm_compare_op1 = operands[1];
+ arm_compare_fp = 1;
+ DONE;
+}
+")
+
+(define_expand "cmpdf"
+ [(match_operand:DF 0 "s_register_operand" "")
+ (match_operand:DF 1 "fpu_rhs_operand" "")]
+ "TARGET_HARD_FLOAT"
+ "
+{
+ arm_compare_op0 = operands[0];
+ arm_compare_op1 = operands[1];
+ arm_compare_fp = 1;
+ DONE;
+}
+")
+
+(define_expand "cmpxf"
+ [(match_operand:XF 0 "s_register_operand" "")
+ (match_operand:XF 1 "fpu_rhs_operand" "")]
+ "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT"
+ "
+{
+ arm_compare_op0 = operands[0];
+ arm_compare_op1 = operands[1];
+ arm_compare_fp = 1;
+ DONE;
+}
+")
+
+(define_insn "*cmpsi_insn"
+ [(set (reg:CC 24)
+ (compare:CC (match_operand:SI 0 "s_register_operand" "r,r")
+ (match_operand:SI 1 "arm_add_operand" "rI,L")))]
+ ""
+ "@
+ cmp%?\\t%0, %1
+ cmn%?\\t%0, #%n1"
+[(set_attr "conds" "set")])
+
+(define_insn "*cmpsi_shiftsi"
+ [(set (reg:CC 24)
+ (compare:CC (match_operand:SI 0 "s_register_operand" "r")
+ (match_operator:SI 3 "shift_operator"
+ [(match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "arm_rhs_operand" "rM")])))]
+ ""
+ "cmp%?\\t%0, %1%S3"
+[(set_attr "conds" "set")])
+
+(define_insn "*cmpsi_shiftsi_swp"
+ [(set (reg:CC_SWP 24)
+ (compare:CC_SWP (match_operator:SI 3 "shift_operator"
+ [(match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "reg_or_int_operand" "rM")])
+ (match_operand:SI 0 "s_register_operand" "r")))]
+ ""
+ "cmp%?\\t%0, %1%S3"
+[(set_attr "conds" "set")])
+
+(define_insn "*cmpsi_neg_shiftsi"
+ [(set (reg:CC 24)
+ (compare:CC (match_operand:SI 0 "s_register_operand" "r")
+ (neg:SI (match_operator:SI 3 "shift_operator"
+ [(match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "arm_rhs_operand" "rM")]))))]
+ ""
+ "cmn%?\\t%0, %1%S3"
+[(set_attr "conds" "set")])
+
+(define_insn "*cmpsf_insn"
+ [(set (reg:CCFP 24)
+ (compare:CCFP (match_operand:SF 0 "s_register_operand" "f,f")
+ (match_operand:SF 1 "fpu_add_operand" "fG,H")))]
+ "TARGET_HARD_FLOAT"
+ "@
+ cmf%?\\t%0, %1
+ cnf%?\\t%0, #%N1"
+[(set_attr "conds" "set")
+ (set_attr "type" "f_2_r")])
+
+(define_insn "*cmpdf_insn"
+ [(set (reg:CCFP 24)
+ (compare:CCFP (match_operand:DF 0 "s_register_operand" "f,f")
+ (match_operand:DF 1 "fpu_add_operand" "fG,H")))]
+ "TARGET_HARD_FLOAT"
+ "@
+ cmf%?\\t%0, %1
+ cnf%?\\t%0, #%N1"
+[(set_attr "conds" "set")
+ (set_attr "type" "f_2_r")])
+
+(define_insn "*cmpesfdf_df"
+ [(set (reg:CCFP 24)
+ (compare:CCFP (float_extend:DF
+ (match_operand:SF 0 "s_register_operand" "f,f"))
+ (match_operand:DF 1 "fpu_add_operand" "fG,H")))]
+ "TARGET_HARD_FLOAT"
+ "@
+ cmf%?\\t%0, %1
+ cnf%?\\t%0, #%N1"
+[(set_attr "conds" "set")
+ (set_attr "type" "f_2_r")])
+
+(define_insn "*cmpdf_esfdf"
+ [(set (reg:CCFP 24)
+ (compare:CCFP (match_operand:DF 0 "s_register_operand" "f")
+ (float_extend:DF
+ (match_operand:SF 1 "s_register_operand" "f"))))]
+ "TARGET_HARD_FLOAT"
+ "cmf%?\\t%0, %1"
+[(set_attr "conds" "set")
+ (set_attr "type" "f_2_r")])
+
+(define_insn "*cmpxf_insn"
+ [(set (reg:CCFP 24)
+ (compare:CCFP (match_operand:XF 0 "s_register_operand" "f,f")
+ (match_operand:XF 1 "fpu_add_operand" "fG,H")))]
+ "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT"
+ "@
+ cmf%?\\t%0, %1
+ cnf%?\\t%0, #%N1"
+[(set_attr "conds" "set")
+ (set_attr "type" "f_2_r")])
+
+(define_insn "*cmpsf_trap"
+ [(set (reg:CCFPE 24)
+ (compare:CCFPE (match_operand:SF 0 "s_register_operand" "f,f")
+ (match_operand:SF 1 "fpu_add_operand" "fG,H")))]
+ "TARGET_HARD_FLOAT"
+ "@
+ cmf%?e\\t%0, %1
+ cnf%?e\\t%0, #%N1"
+[(set_attr "conds" "set")
+ (set_attr "type" "f_2_r")])
+
+(define_insn "*cmpdf_trap"
+ [(set (reg:CCFPE 24)
+ (compare:CCFPE (match_operand:DF 0 "s_register_operand" "f,f")
+ (match_operand:DF 1 "fpu_add_operand" "fG,H")))]
+ "TARGET_HARD_FLOAT"
+ "@
+ cmf%?e\\t%0, %1
+ cnf%?e\\t%0, #%N1"
+[(set_attr "conds" "set")
+ (set_attr "type" "f_2_r")])
+
+(define_insn "*cmp_esfdf_df_trap"
+ [(set (reg:CCFPE 24)
+ (compare:CCFPE (float_extend:DF
+ (match_operand:SF 0 "s_register_operand" "f,f"))
+ (match_operand:DF 1 "fpu_add_operand" "fG,H")))]
+ "TARGET_HARD_FLOAT"
+ "@
+ cmf%?e\\t%0, %1
+ cnf%?e\\t%0, #%N1"
+[(set_attr "conds" "set")
+ (set_attr "type" "f_2_r")])
+
+(define_insn "*cmp_df_esfdf_trap"
+ [(set (reg:CCFPE 24)
+ (compare:CCFPE (match_operand:DF 0 "s_register_operand" "f")
+ (float_extend:DF
+ (match_operand:SF 1 "s_register_operand" "f"))))]
+ "TARGET_HARD_FLOAT"
+ "cmf%?e\\t%0, %1"
+[(set_attr "conds" "set")
+ (set_attr "type" "f_2_r")])
+
+(define_insn "*cmpxf_trap"
+ [(set (reg:CCFPE 24)
+ (compare:CCFPE (match_operand:XF 0 "s_register_operand" "f,f")
+ (match_operand:XF 1 "fpu_add_operand" "fG,H")))]
+ "ENABLE_XF_PATTERNS && TARGET_HARD_FLOAT"
+ "@
+ cmf%?e\\t%0, %1
+ cnf%?e\\t%0, #%N1"
+[(set_attr "conds" "set")
+ (set_attr "type" "f_2_r")])
+
+; This insn allows redundant compares to be removed by cse, nothing should
+; ever appear in the output file since (set (reg x) (reg x)) is a no-op that
+; is deleted later on. The match_dup will match the mode here, so that
+; mode changes of the condition codes aren't lost by this even though we don't
+; specify what they are.
+
+(define_insn "*deleted_compare"
+ [(set (match_operand 0 "cc_register" "") (match_dup 0))]
+ ""
+ "\\t%@ deleted compare"
+[(set_attr "conds" "set")
+ (set_attr "length" "0")])
+
+
+;; Conditional branch insns
+
+(define_expand "beq"
+ [(set (pc)
+ (if_then_else (eq (match_dup 1) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{
+ operands[1] = gen_compare_reg (EQ, arm_compare_op0, arm_compare_op1,
+ arm_compare_fp);
+}
+")
+
+(define_expand "bne"
+ [(set (pc)
+ (if_then_else (ne (match_dup 1) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{
+ operands[1] = gen_compare_reg (NE, arm_compare_op0, arm_compare_op1,
+ arm_compare_fp);
+}
+")
+
+(define_expand "bgt"
+ [(set (pc)
+ (if_then_else (gt (match_dup 1) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{
+ operands[1] = gen_compare_reg (GT, arm_compare_op0, arm_compare_op1,
+ arm_compare_fp);
+}
+")
+
+(define_expand "ble"
+ [(set (pc)
+ (if_then_else (le (match_dup 1) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{
+ operands[1] = gen_compare_reg (LE, arm_compare_op0, arm_compare_op1,
+ arm_compare_fp);
+}
+")
+
+(define_expand "bge"
+ [(set (pc)
+ (if_then_else (ge (match_dup 1) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{
+ operands[1] = gen_compare_reg (GE, arm_compare_op0, arm_compare_op1,
+ arm_compare_fp);
+}
+")
+
+(define_expand "blt"
+ [(set (pc)
+ (if_then_else (lt (match_dup 1) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{
+ operands[1] = gen_compare_reg (LT, arm_compare_op0, arm_compare_op1,
+ arm_compare_fp);
+}
+")
+
+(define_expand "bgtu"
+ [(set (pc)
+ (if_then_else (gtu (match_dup 1) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{
+ operands[1] = gen_compare_reg (GTU, arm_compare_op0, arm_compare_op1,
+ arm_compare_fp);
+}
+")
+
+(define_expand "bleu"
+ [(set (pc)
+ (if_then_else (leu (match_dup 1) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{
+ operands[1] = gen_compare_reg (LEU, arm_compare_op0, arm_compare_op1,
+ arm_compare_fp);
+}
+")
+
+(define_expand "bgeu"
+ [(set (pc)
+ (if_then_else (geu (match_dup 1) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{
+ operands[1] = gen_compare_reg (GEU, arm_compare_op0, arm_compare_op1,
+ arm_compare_fp);
+}
+")
+
+(define_expand "bltu"
+ [(set (pc)
+ (if_then_else (ltu (match_dup 1) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{
+ operands[1] = gen_compare_reg (LTU, arm_compare_op0, arm_compare_op1,
+ arm_compare_fp);
+}
+")
+
+;; patterns to match conditional branch insns
+
+(define_insn "*condbranch"
+ [(set (pc)
+ (if_then_else (match_operator 1 "comparison_operator"
+ [(match_operand 2 "cc_register" "") (const_int 0)])
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "*
+{
+ extern int arm_ccfsm_state;
+
+ if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2)
+ {
+ arm_ccfsm_state += 2;
+ return \"\";
+ }
+ return \"b%d1\\t%l0\";
+}"
+[(set_attr "conds" "use")])
+
+(define_insn "*condbranch_reversed"
+ [(set (pc)
+ (if_then_else (match_operator 1 "comparison_operator"
+ [(match_operand 2 "cc_register" "") (const_int 0)])
+ (pc)
+ (label_ref (match_operand 0 "" ""))))]
+ ""
+ "*
+{
+ extern int arm_ccfsm_state;
+
+ if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2)
+ {
+ arm_ccfsm_state += 2;
+ return \"\";
+ }
+ return \"b%D1\\t%l0\";
+}"
+[(set_attr "conds" "use")])
+
+
+; scc insns
+
+(define_expand "seq"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (eq:SI (match_dup 1) (const_int 0)))]
+ ""
+ "
+{
+ operands[1] = gen_compare_reg (EQ, arm_compare_op0, arm_compare_op1,
+ arm_compare_fp);
+}
+")
+
+(define_expand "sne"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (ne:SI (match_dup 1) (const_int 0)))]
+ ""
+ "
+{
+ operands[1] = gen_compare_reg (NE, arm_compare_op0, arm_compare_op1,
+ arm_compare_fp);
+}
+")
+
+(define_expand "sgt"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (gt:SI (match_dup 1) (const_int 0)))]
+ ""
+ "
+{
+ operands[1] = gen_compare_reg (GT, arm_compare_op0, arm_compare_op1,
+ arm_compare_fp);
+}
+")
+
+(define_expand "sle"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (le:SI (match_dup 1) (const_int 0)))]
+ ""
+ "
+{
+ operands[1] = gen_compare_reg (LE, arm_compare_op0, arm_compare_op1,
+ arm_compare_fp);
+}
+")
+
+(define_expand "sge"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (ge:SI (match_dup 1) (const_int 0)))]
+ ""
+ "
+{
+ operands[1] = gen_compare_reg (GE, arm_compare_op0, arm_compare_op1,
+ arm_compare_fp);
+}
+")
+
+(define_expand "slt"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (lt:SI (match_dup 1) (const_int 0)))]
+ ""
+ "
+{
+ operands[1] = gen_compare_reg (LT, arm_compare_op0, arm_compare_op1,
+ arm_compare_fp);
+}
+")
+
+(define_expand "sgtu"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (gtu:SI (match_dup 1) (const_int 0)))]
+ ""
+ "
+{
+ operands[1] = gen_compare_reg (GTU, arm_compare_op0, arm_compare_op1,
+ arm_compare_fp);
+}
+")
+
+(define_expand "sleu"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (leu:SI (match_dup 1) (const_int 0)))]
+ ""
+ "
+{
+ operands[1] = gen_compare_reg (LEU, arm_compare_op0, arm_compare_op1,
+ arm_compare_fp);
+}
+")
+
+(define_expand "sgeu"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (geu:SI (match_dup 1) (const_int 0)))]
+ ""
+ "
+{
+ operands[1] = gen_compare_reg (GEU, arm_compare_op0, arm_compare_op1,
+ arm_compare_fp);
+}
+")
+
+(define_expand "sltu"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (ltu:SI (match_dup 1) (const_int 0)))]
+ ""
+ "
+{
+ operands[1] = gen_compare_reg (LTU, arm_compare_op0, arm_compare_op1,
+ arm_compare_fp);
+}
+")
+
+(define_insn "*mov_scc"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (match_operator:SI 1 "comparison_operator"
+ [(match_operand 2 "cc_register" "") (const_int 0)]))]
+ ""
+ "mov%D1\\t%0, #0\;mov%d1\\t%0, #1"
+[(set_attr "conds" "use")
+ (set_attr "length" "8")])
+
+(define_insn "*mov_negscc"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (neg:SI (match_operator:SI 1 "comparison_operator"
+ [(match_operand 2 "cc_register" "") (const_int 0)])))]
+ ""
+ "mov%D1\\t%0, #0\;mvn%d1\\t%0, #0"
+[(set_attr "conds" "use")
+ (set_attr "length" "8")])
+
+(define_insn "*mov_notscc"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (not:SI (match_operator:SI 1 "comparison_operator"
+ [(match_operand 2 "cc_register" "") (const_int 0)])))]
+ ""
+ "mov%D1\\t%0, #0\;mvn%d1\\t%0, #1"
+[(set_attr "conds" "use")
+ (set_attr "length" "8")])
+
+
+;; Conditional move insns
+
+(define_expand "movsicc"
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (if_then_else:SI (match_operand 1 "comparison_operator" "")
+ (match_operand:SI 2 "arm_not_operand" "")
+ (match_operand:SI 3 "arm_not_operand" "")))]
+ ""
+ "
+{
+ enum rtx_code code = GET_CODE (operands[1]);
+ rtx ccreg = gen_compare_reg (code, arm_compare_op0, arm_compare_op1,
+ arm_compare_fp);
+
+ operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx);
+}")
+
+(define_expand "movsfcc"
+ [(set (match_operand:SF 0 "s_register_operand" "")
+ (if_then_else:SF (match_operand 1 "comparison_operator" "")
+ (match_operand:SF 2 "s_register_operand" "")
+ (match_operand:SF 3 "nonmemory_operand" "")))]
+ ""
+ "
+{
+ enum rtx_code code = GET_CODE (operands[1]);
+ rtx ccreg;
+
+ /* When compiling for SOFT_FLOAT, ensure both arms are in registers.
+ Otherwise, ensure it is a valid FP add operand */
+ if ((! TARGET_HARD_FLOAT)
+ || (! fpu_add_operand (operands[3], SFmode)))
+ operands[3] = force_reg (SFmode, operands[3]);
+
+ ccreg = gen_compare_reg (code, arm_compare_op0, arm_compare_op1,
+ arm_compare_fp);
+
+ operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx);
+}")
+
+(define_expand "movdfcc"
+ [(set (match_operand:DF 0 "s_register_operand" "")
+ (if_then_else:DF (match_operand 1 "comparison_operator" "")
+ (match_operand:DF 2 "s_register_operand" "")
+ (match_operand:DF 3 "fpu_add_operand" "")))]
+ "TARGET_HARD_FLOAT"
+ "
+{
+ enum rtx_code code = GET_CODE (operands[1]);
+ rtx ccreg = gen_compare_reg (code, arm_compare_op0, arm_compare_op1,
+ arm_compare_fp);
+
+ operands[1] = gen_rtx (code, VOIDmode, ccreg, const0_rtx);
+}")
+
+(define_insn "*movsicc_insn"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r,r,r,r,r")
+ (if_then_else:SI
+ (match_operator 3 "comparison_operator"
+ [(match_operand 4 "cc_register" "") (const_int 0)])
+ (match_operand:SI 1 "arm_not_operand" "0,0,rI,K,rI,rI,K,K")
+ (match_operand:SI 2 "arm_not_operand" "rI,K,0,0,rI,K,rI,K")))]
+ ""
+ "@
+ mov%D3\\t%0, %2
+ mvn%D3\\t%0, #%B2
+ mov%d3\\t%0, %1
+ mvn%d3\\t%0, #%B1
+ mov%d3\\t%0, %1\;mov%D3\\t%0, %2
+ mov%d3\\t%0, %1\;mvn%D3\\t%0, #%B2
+ mvn%d3\\t%0, #%B1\;mov%D3\\t%0, %2
+ mvn%d3\\t%0, #%B1\;mvn%D3\\t%0, #%B2"
+ [(set_attr "length" "4,4,4,4,8,8,8,8")
+ (set_attr "conds" "use")])
+
+(define_insn "*movsfcc_hard_insn"
+ [(set (match_operand:SF 0 "s_register_operand" "=f,f,f,f,f,f,f,f")
+ (if_then_else:SF
+ (match_operator 3 "comparison_operator"
+ [(match_operand 4 "cc_register" "") (const_int 0)])
+ (match_operand:SF 1 "fpu_add_operand" "0,0,fG,H,fG,fG,H,H")
+ (match_operand:SF 2 "fpu_add_operand" "fG,H,0,0,fG,H,fG,H")))]
+ "TARGET_HARD_FLOAT"
+ "@
+ mvf%D3s\\t%0, %2
+ mnf%D3s\\t%0, #%N2
+ mvf%d3s\\t%0, %1
+ mnf%d3s\\t%0, #%N1
+ mvf%d3s\\t%0, %1\;mvf%D3s\\t%0, %2
+ mvf%d3s\\t%0, %1\;mnf%D3s\\t%0, #%N2
+ mnf%d3s\\t%0, #%N1\;mvf%D3s\\t%0, %2
+ mnf%d3s\\t%0, #%N1\;mnf%D3s\\t%0, #%N2"
+ [(set_attr "length" "4,4,4,4,8,8,8,8")
+ (set_attr "type" "ffarith")
+ (set_attr "conds" "use")])
+
+(define_insn "*movsfcc_soft_insn"
+ [(set (match_operand:SF 0 "s_register_operand" "=r,r")
+ (if_then_else:SF (match_operator 3 "comparison_operator"
+ [(match_operand 4 "cc_register" "") (const_int 0)])
+ (match_operand:SF 1 "s_register_operand" "0,r")
+ (match_operand:SF 2 "s_register_operand" "r,0")))]
+ "TARGET_SOFT_FLOAT"
+ "@
+ mov%D3\\t%0, %2
+ mov%d3\\t%0, %1"
+ [(set_attr "conds" "use")])
+
+(define_insn "*movdfcc_insn"
+ [(set (match_operand:DF 0 "s_register_operand" "=f,f,f,f,f,f,f,f")
+ (if_then_else:DF
+ (match_operator 3 "comparison_operator"
+ [(match_operand 4 "cc_register" "") (const_int 0)])
+ (match_operand:DF 1 "fpu_add_operand" "0,0,fG,H,fG,fG,H,H")
+ (match_operand:DF 2 "fpu_add_operand" "fG,H,0,0,fG,H,fG,H")))]
+ "TARGET_HARD_FLOAT"
+ "@
+ mvf%D3d\\t%0, %2
+ mnf%D3d\\t%0, #%N2
+ mvf%d3d\\t%0, %1
+ mnf%d3d\\t%0, #%N1
+ mvf%d3d\\t%0, %1\;mvf%D3d\\t%0, %2
+ mvf%d3d\\t%0, %1\;mnf%D3d\\t%0, #%N2
+ mnf%d3d\\t%0, #%N1\;mvf%D3d\\t%0, %2
+ mnf%d3d\\t%0, #%N1\;mnf%D3d\\t%0, #%N2"
+ [(set_attr "length" "4,4,4,4,8,8,8,8")
+ (set_attr "type" "ffarith")
+ (set_attr "conds" "use")])
+
+;; Jump and linkage insns
+
+(define_insn "jump"
+ [(set (pc)
+ (label_ref (match_operand 0 "" "")))]
+ ""
+ "*
+{
+ extern int arm_ccfsm_state;
+
+ if (arm_ccfsm_state == 1 || arm_ccfsm_state == 2)
+ {
+ arm_ccfsm_state += 2;
+ return \"\";
+ }
+ return \"b%?\\t%l0\";
+}")
+
+(define_expand "call"
+ [(parallel [(call (match_operand 0 "memory_operand" "")
+ (match_operand 1 "general_operand" ""))
+ (clobber (reg:SI 14))])]
+ ""
+ "
+{
+ if (TARGET_LONG_CALLS && GET_CODE (XEXP (operands[0], 0)) != REG)
+ XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0));
+}")
+
+(define_insn "*call_reg"
+ [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r"))
+ (match_operand 1 "" "g"))
+ (clobber (reg:SI 14))]
+ ""
+ "*
+ return output_call (operands);
+"
+;; length is worst case, normally it is only two
+[(set_attr "length" "12")
+ (set_attr "type" "call")])
+
+(define_insn "*call_mem"
+ [(call (mem:SI (match_operand 0 "memory_operand" "m"))
+ (match_operand 1 "general_operand" "g"))
+ (clobber (reg:SI 14))]
+ ""
+ "*
+ return output_call_mem (operands);
+"
+[(set_attr "length" "12")
+ (set_attr "type" "call")])
+
+(define_expand "call_value"
+ [(parallel [(set (match_operand 0 "" "=rf")
+ (call (match_operand 1 "memory_operand" "m")
+ (match_operand 2 "general_operand" "g")))
+ (clobber (reg:SI 14))])]
+ ""
+ "
+{
+ if (TARGET_LONG_CALLS && GET_CODE (XEXP (operands[1], 0)) != REG)
+ XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0));
+}")
+
+(define_insn "*call_value_reg"
+ [(set (match_operand 0 "" "=rf")
+ (call (mem:SI (match_operand:SI 1 "s_register_operand" "r"))
+ (match_operand 2 "general_operand" "g")))
+ (clobber (reg:SI 14))]
+ ""
+ "*
+ return output_call (&operands[1]);
+"
+[(set_attr "length" "12")
+ (set_attr "type" "call")])
+
+(define_insn "*call_value_mem"
+ [(set (match_operand 0 "" "=rf")
+ (call (mem:SI (match_operand 1 "memory_operand" "m"))
+ (match_operand 2 "general_operand" "g")))
+ (clobber (reg:SI 14))]
+ "! CONSTANT_ADDRESS_P (XEXP (operands[1], 0))"
+ "*
+ return output_call_mem (&operands[1]);
+"
+[(set_attr "length" "12")
+ (set_attr "type" "call")])
+
+;; Allow calls to SYMBOL_REFs specially as they are not valid general addresses
+;; The 'a' causes the operand to be treated as an address, i.e. no '#' output.
+
+(define_insn "*call_symbol"
+ [(call (mem:SI (match_operand:SI 0 "" "X"))
+ (match_operand:SI 1 "general_operand" "g"))
+ (clobber (reg:SI 14))]
+ "! TARGET_LONG_CALLS && GET_CODE (operands[0]) == SYMBOL_REF"
+ "bl%?\\t%a0"
+[(set_attr "type" "call")])
+
+(define_insn "*call_value_symbol"
+ [(set (match_operand 0 "s_register_operand" "=rf")
+ (call (mem:SI (match_operand:SI 1 "" "X"))
+ (match_operand:SI 2 "general_operand" "g")))
+ (clobber (reg:SI 14))]
+ "! TARGET_LONG_CALLS && GET_CODE(operands[1]) == SYMBOL_REF"
+ "bl%?\\t%a1"
+[(set_attr "type" "call")])
+
+;; Often the return insn will be the same as loading from memory, so set attr
+(define_insn "return"
+ [(return)]
+ "USE_RETURN_INSN (FALSE)"
+ "*
+{
+ extern int arm_ccfsm_state;
+
+ if (arm_ccfsm_state == 2)
+ {
+ arm_ccfsm_state += 2;
+ return \"\";
+ }
+ return output_return_instruction (NULL, TRUE, FALSE);
+}"
+[(set_attr "type" "load")])
+
+(define_insn "*cond_return"
+ [(set (pc)
+ (if_then_else (match_operator 0 "comparison_operator"
+ [(match_operand 1 "cc_register" "") (const_int 0)])
+ (return)
+ (pc)))]
+ "USE_RETURN_INSN (TRUE)"
+ "*
+{
+ extern int arm_ccfsm_state;
+
+ if (arm_ccfsm_state == 2)
+ {
+ arm_ccfsm_state += 2;
+ return \"\";
+ }
+ return output_return_instruction (operands[0], TRUE, FALSE);
+}"
+[(set_attr "conds" "use")
+ (set_attr "type" "load")])
+
+(define_insn "*cond_return_inverted"
+ [(set (pc)
+ (if_then_else (match_operator 0 "comparison_operator"
+ [(match_operand 1 "cc_register" "") (const_int 0)])
+ (pc)
+ (return)))]
+ "USE_RETURN_INSN (TRUE)"
+ "*
+{
+ extern int arm_ccfsm_state;
+
+ if (arm_ccfsm_state == 2)
+ {
+ arm_ccfsm_state += 2;
+ return \"\";
+ }
+ return output_return_instruction (operands[0], TRUE, TRUE);
+}"
+[(set_attr "conds" "use")
+ (set_attr "type" "load")])
+
+;; Call subroutine returning any type.
+
+(define_expand "untyped_call"
+ [(parallel [(call (match_operand 0 "" "")
+ (const_int 0))
+ (match_operand 1 "" "")
+ (match_operand 2 "" "")])]
+ ""
+ "
+{
+ int i;
+
+ emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
+
+ for (i = 0; i < XVECLEN (operands[2], 0); i++)
+ {
+ rtx set = XVECEXP (operands[2], 0, i);
+ emit_move_insn (SET_DEST (set), SET_SRC (set));
+ }
+
+ /* The optimizer does not know that the call sets the function value
+ registers we stored in the result block. We avoid problems by
+ claiming that all hard registers are used and clobbered at this
+ point. */
+ emit_insn (gen_blockage ());
+
+ DONE;
+}")
+
+;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
+;; all of memory. This blocks insns from being moved across this point.
+
+(define_insn "blockage"
+ [(unspec_volatile [(const_int 0)] 0)]
+ ""
+ ""
+[(set_attr "length" "0")
+ (set_attr "type" "block")])
+
+(define_expand "casesi"
+ [(match_operand:SI 0 "s_register_operand" "") ; index to jump on
+ (match_operand:SI 1 "const_int_operand" "") ; lower bound
+ (match_operand:SI 2 "const_int_operand" "") ; total range
+ (match_operand:SI 3 "" "") ; table label
+ (match_operand:SI 4 "" "")] ; Out of range label
+ ""
+ "
+{
+ rtx reg;
+ if (operands[1] != const0_rtx)
+ {
+ reg = gen_reg_rtx (SImode);
+ emit_insn (gen_addsi3 (reg, operands[0],
+ GEN_INT (-INTVAL (operands[1]))));
+ operands[0] = reg;
+ }
+
+ if (! const_ok_for_arm (INTVAL (operands[2])))
+ operands[2] = force_reg (SImode, operands[2]);
+
+ emit_jump_insn (gen_casesi_internal (operands[0], operands[2], operands[3],
+ operands[4]));
+ DONE;
+}")
+
+;; The USE in this pattern is needed to tell flow analysis that this is
+;; a CASESI insn. It has no other purpose.
+(define_insn "casesi_internal"
+ [(parallel [(set (pc)
+ (if_then_else
+ (leu (match_operand:SI 0 "s_register_operand" "r")
+ (match_operand:SI 1 "arm_rhs_operand" "rI"))
+ (mem:SI (plus:SI (mult:SI (match_dup 0) (const_int 4))
+ (label_ref (match_operand 2 "" ""))))
+ (label_ref (match_operand 3 "" ""))))
+ (use (label_ref (match_dup 2)))])]
+ ""
+ "*
+ if (flag_pic)
+ return \"cmp\\t%0, %1\;addls\\t%|pc, %|pc, %0, asl #2\;b\\t%l3\";
+ return \"cmp\\t%0, %1\;ldrls\\t%|pc, [%|pc, %0, asl #2]\;b\\t%l3\";
+"
+[(set_attr "conds" "clob")
+ (set_attr "length" "12")])
+
+(define_insn "indirect_jump"
+ [(set (pc)
+ (match_operand:SI 0 "s_register_operand" "r"))]
+ ""
+ "mov%?\\t%|pc, %0\\t%@ indirect jump")
+
+(define_insn "*load_indirect_jump"
+ [(set (pc)
+ (match_operand:SI 0 "memory_operand" "m"))]
+ ""
+ "ldr%?\\t%|pc, %0\\t%@ indirect jump"
+[(set_attr "type" "load")])
+
+;; Misc insns
+
+(define_insn "nop"
+ [(const_int 0)]
+ ""
+ "mov%?\\tr0, r0\\t%@ nop")
+
+;; Patterns to allow combination of arithmetic, cond code and shifts
+
+(define_insn "*arith_shiftsi"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (match_operator:SI 1 "shiftable_operator"
+ [(match_operator:SI 3 "shift_operator"
+ [(match_operand:SI 4 "s_register_operand" "r")
+ (match_operand:SI 5 "reg_or_int_operand" "rI")])
+ (match_operand:SI 2 "s_register_operand" "r")]))]
+ ""
+ "%i1%?\\t%0, %2, %4%S3")
+
+(define_insn "*arith_shiftsi_compare0"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV (match_operator:SI 1 "shiftable_operator"
+ [(match_operator:SI 3 "shift_operator"
+ [(match_operand:SI 4 "s_register_operand" "r")
+ (match_operand:SI 5 "reg_or_int_operand" "rI")])
+ (match_operand:SI 2 "s_register_operand" "r")])
+ (const_int 0)))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (match_op_dup 1 [(match_op_dup 3 [(match_dup 4) (match_dup 5)])
+ (match_dup 2)]))]
+ ""
+ "%i1%?s\\t%0, %2, %4%S3"
+[(set_attr "conds" "set")])
+
+(define_insn "*arith_shiftsi_compare0_scratch"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV (match_operator:SI 1 "shiftable_operator"
+ [(match_operator:SI 3 "shift_operator"
+ [(match_operand:SI 4 "s_register_operand" "r")
+ (match_operand:SI 5 "reg_or_int_operand" "rI")])
+ (match_operand:SI 2 "s_register_operand" "r")])
+ (const_int 0)))
+ (clobber (match_scratch:SI 0 "=r"))]
+ ""
+ "%i1%?s\\t%0, %2, %4%S3"
+[(set_attr "conds" "set")])
+
+(define_insn "*sub_shiftsi"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (minus:SI (match_operand:SI 1 "s_register_operand" "r")
+ (match_operator:SI 2 "shift_operator"
+ [(match_operand:SI 3 "s_register_operand" "r")
+ (match_operand:SI 4 "reg_or_int_operand" "rM")])))]
+ ""
+ "sub%?\\t%0, %1, %3%S2")
+
+(define_insn "*sub_shiftsi_compare0"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV
+ (minus:SI (match_operand:SI 1 "s_register_operand" "r")
+ (match_operator:SI 2 "shift_operator"
+ [(match_operand:SI 3 "s_register_operand" "r")
+ (match_operand:SI 4 "reg_or_int_operand" "rM")]))
+ (const_int 0)))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3)
+ (match_dup 4)])))]
+ ""
+ "sub%?s\\t%0, %1, %3%S2"
+[(set_attr "conds" "set")])
+
+(define_insn "*sub_shiftsi_compare0_scratch"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV
+ (minus:SI (match_operand:SI 1 "s_register_operand" "r")
+ (match_operator:SI 2 "shift_operator"
+ [(match_operand:SI 3 "s_register_operand" "r")
+ (match_operand:SI 4 "reg_or_int_operand" "rM")]))
+ (const_int 0)))
+ (clobber (match_scratch:SI 0 "=r"))]
+ ""
+ "sub%?s\\t%0, %1, %3%S2"
+[(set_attr "conds" "set")])
+
+;; These variants of the above insns can occur if the first operand is the
+;; frame pointer and we eliminate that. This is a kludge, but there doesn't
+;; seem to be a way around it. Most of the predicates have to be null
+;; because the format can be generated part way through reload, so
+;; if we don't match it as soon as it becomes available, reload doesn't know
+;; how to reload pseudos that haven't got hard registers; the constraints will
+;; sort everything out.
+
+(define_insn "*reload_mulsi3"
+ [(set (match_operand:SI 0 "" "=&r")
+ (plus:SI (plus:SI (match_operator:SI 5 "shift_operator"
+ [(match_operand:SI 3 "" "r")
+ (match_operand:SI 4 "" "rM")])
+ (match_operand:SI 2 "" "r"))
+ (match_operand:SI 1 "const_int_operand" "n")))]
+ "reload_in_progress"
+ "*
+ output_asm_insn (\"add%?\\t%0, %2, %3%S5\", operands);
+ operands[2] = operands[1];
+ operands[1] = operands[0];
+ return output_add_immediate (operands);
+"
+; we have no idea how long the add_immediate is, it could be up to 4.
+[(set_attr "length" "20")])
+
+(define_insn "*reload_mulsi_compare0"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV (plus:SI
+ (plus:SI
+ (match_operator:SI 5 "shift_operator"
+ [(match_operand:SI 3 "" "r")
+ (match_operand:SI 4 "" "rM")])
+ (match_operand:SI 1 "" "r"))
+ (match_operand:SI 2 "const_int_operand" "n"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "" "=&r")
+ (plus:SI (plus:SI (match_op_dup 5 [(match_dup 3) (match_dup 4)])
+ (match_dup 1))
+ (match_dup 2)))]
+ "reload_in_progress"
+ "*
+ output_add_immediate (operands);
+ return \"add%?s\\t%0, %0, %3%S5\";
+"
+[(set_attr "conds" "set")
+ (set_attr "length" "20")])
+
+(define_insn "*reload_mulsi_compare0_scratch"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV (plus:SI
+ (plus:SI
+ (match_operator:SI 5 "shift_operator"
+ [(match_operand:SI 3 "" "r")
+ (match_operand:SI 4 "" "rM")])
+ (match_operand:SI 1 "" "r"))
+ (match_operand:SI 2 "const_int_operand" "n"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 0 "=&r"))]
+ "reload_in_progress"
+ "*
+ output_add_immediate (operands);
+ return \"add%?s\\t%0, %0, %3%S5\";
+"
+[(set_attr "conds" "set")
+ (set_attr "length" "20")])
+
+;; These are similar, but are needed when the mla pattern contains the
+;; eliminated register as operand 3.
+
+(define_insn "*reload_muladdsi"
+ [(set (match_operand:SI 0 "" "=&r,&r")
+ (plus:SI (plus:SI (mult:SI (match_operand:SI 1 "" "%0,r")
+ (match_operand:SI 2 "" "r,r"))
+ (match_operand:SI 3 "" "r,r"))
+ (match_operand:SI 4 "const_int_operand" "n,n")))]
+ "reload_in_progress"
+ "*
+ output_asm_insn (\"mla%?\\t%0, %2, %1, %3\", operands);
+ operands[2] = operands[4];
+ operands[1] = operands[0];
+ return output_add_immediate (operands);
+"
+[(set_attr "length" "20")
+ (set_attr "type" "mult")])
+
+(define_insn "*reload_muladdsi_compare0"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV (plus:SI (plus:SI (mult:SI
+ (match_operand:SI 3 "" "r")
+ (match_operand:SI 4 "" "r"))
+ (match_operand:SI 1 "" "r"))
+ (match_operand:SI 2 "const_int_operand" "n"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "" "=&r")
+ (plus:SI (plus:SI (mult:SI (match_dup 3) (match_dup 4)) (match_dup 1))
+ (match_dup 2)))]
+ "reload_in_progress"
+ "*
+ output_add_immediate (operands);
+ output_asm_insn (\"mla%?s\\t%0, %3, %4, %0\", operands);
+ return \"\";
+"
+[(set_attr "length" "20")
+ (set_attr "conds" "set")
+ (set_attr "type" "mult")])
+
+(define_insn "*reload_muladdsi_compare0_scratch"
+ [(set (reg:CC_NOOV 24)
+ (compare:CC_NOOV (plus:SI (plus:SI (mult:SI
+ (match_operand:SI 3 "" "r")
+ (match_operand:SI 4 "" "r"))
+ (match_operand:SI 1 "" "r"))
+ (match_operand:SI 2 "const_int_operand" "n"))
+ (const_int 0)))
+ (clobber (match_scratch:SI 0 "=&r"))]
+ "reload_in_progress"
+ "*
+ output_add_immediate (operands);
+ return \"mla%?s\\t%0, %3, %4, %0\";
+"
+[(set_attr "length" "20")
+ (set_attr "conds" "set")
+ (set_attr "type" "mult")])
+
+
+
+(define_insn "*and_scc"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (and:SI (match_operator 1 "comparison_operator"
+ [(match_operand 3 "cc_register" "") (const_int 0)])
+ (match_operand:SI 2 "s_register_operand" "r")))]
+ ""
+ "mov%D1\\t%0, #0\;and%d1\\t%0, %2, #1"
+[(set_attr "conds" "use")
+ (set_attr "length" "8")])
+
+(define_insn "*ior_scc"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (ior:SI (match_operator 2 "comparison_operator"
+ [(match_operand 3 "cc_register" "") (const_int 0)])
+ (match_operand:SI 1 "s_register_operand" "0,?r")))]
+ ""
+ "@
+ orr%d2\\t%0, %1, #1
+ mov%D2\\t%0, %1\;orr%d2\\t%0, %1, #1"
+[(set_attr "conds" "use")
+ (set_attr "length" "4,8")])
+
+(define_insn "*compare_scc"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (match_operator 1 "comparison_operator"
+ [(match_operand:SI 2 "s_register_operand" "r,r")
+ (match_operand:SI 3 "arm_add_operand" "rI,L")]))
+ (clobber (reg:CC 24))]
+ ""
+ "*
+ if (GET_CODE (operands[1]) == LT && operands[3] == const0_rtx)
+ return \"mov\\t%0, %2, lsr #31\";
+
+ if (GET_CODE (operands[1]) == GE && operands[3] == const0_rtx)
+ return \"mvn\\t%0, %2\;mov\\t%0, %0, lsr #31\";
+
+ if (GET_CODE (operands[1]) == NE)
+ {
+ if (which_alternative == 1)
+ return \"adds\\t%0, %2, #%n3\;movne\\t%0, #1\";
+ return \"subs\\t%0, %2, %3\;movne\\t%0, #1\";
+ }
+ if (which_alternative == 1)
+ output_asm_insn (\"cmn\\t%2, #%n3\", operands);
+ else
+ output_asm_insn (\"cmp\\t%2, %3\", operands);
+ return \"mov%D1\\t%0, #0\;mov%d1\\t%0, #1\";
+"
+[(set_attr "conds" "clob")
+ (set_attr "length" "12")])
+
+(define_insn "*cond_move"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
+ (if_then_else:SI (match_operator 3 "equality_operator"
+ [(match_operator 4 "comparison_operator"
+ [(match_operand 5 "cc_register" "") (const_int 0)])
+ (const_int 0)])
+ (match_operand:SI 1 "arm_rhs_operand" "0,rI,?rI")
+ (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")))]
+ ""
+ "*
+ if (GET_CODE (operands[3]) == NE)
+ {
+ if (which_alternative != 1)
+ output_asm_insn (\"mov%D4\\t%0, %2\", operands);
+ if (which_alternative != 0)
+ output_asm_insn (\"mov%d4\\t%0, %1\", operands);
+ return \"\";
+ }
+ if (which_alternative != 0)
+ output_asm_insn (\"mov%D4\\t%0, %1\", operands);
+ if (which_alternative != 1)
+ output_asm_insn (\"mov%d4\\t%0, %2\", operands);
+ return \"\";
+"
+[(set_attr "conds" "use")
+ (set_attr "length" "4,4,8")])
+
+(define_insn "*cond_arith"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (match_operator:SI 5 "shiftable_operator"
+ [(match_operator:SI 4 "comparison_operator"
+ [(match_operand:SI 2 "s_register_operand" "r,r")
+ (match_operand:SI 3 "arm_rhs_operand" "rI,rI")])
+ (match_operand:SI 1 "s_register_operand" "0,?r")]))
+ (clobber (reg:CC 24))]
+ ""
+ "*
+ if (GET_CODE (operands[4]) == LT && operands[3] == const0_rtx)
+ return \"%i5\\t%0, %1, %2, lsr #31\";
+
+ output_asm_insn (\"cmp\\t%2, %3\", operands);
+ if (GET_CODE (operands[5]) == AND)
+ output_asm_insn (\"mov%D4\\t%0, #0\", operands);
+ else if (GET_CODE (operands[5]) == MINUS)
+ output_asm_insn (\"rsb%D4\\t%0, %1, #0\", operands);
+ else if (which_alternative != 0)
+ output_asm_insn (\"mov%D4\\t%0, %1\", operands);
+ return \"%i5%d4\\t%0, %1, #1\";
+"
+[(set_attr "conds" "clob")
+ (set_attr "length" "12")])
+
+(define_insn "*cond_sub"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (minus:SI (match_operand:SI 1 "s_register_operand" "0,?r")
+ (match_operator:SI 4 "comparison_operator"
+ [(match_operand:SI 2 "s_register_operand" "r,r")
+ (match_operand:SI 3 "arm_rhs_operand" "rI,rI")])))
+ (clobber (reg:CC 24))]
+ ""
+ "*
+ output_asm_insn (\"cmp\\t%2, %3\", operands);
+ if (which_alternative != 0)
+ output_asm_insn (\"mov%D4\\t%0, %1\", operands);
+ return \"sub%d4\\t%0, %1, #1\";
+"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8,12")])
+
+(define_insn "*cmp_ite0"
+ [(set (match_operand 6 "dominant_cc_register" "")
+ (compare
+ (if_then_else:SI
+ (match_operator 4 "comparison_operator"
+ [(match_operand:SI 0 "s_register_operand" "r,r,r,r")
+ (match_operand:SI 1 "arm_add_operand" "rI,L,rI,L")])
+ (match_operator:SI 5 "comparison_operator"
+ [(match_operand:SI 2 "s_register_operand" "r,r,r,r")
+ (match_operand:SI 3 "arm_add_operand" "rI,rI,L,L")])
+ (const_int 0))
+ (const_int 0)))]
+ ""
+ "*
+{
+ char* opcodes[4][2] =
+ {
+ {\"cmp\\t%2, %3\;cmp%d5\\t%0, %1\",\"cmp\\t%0, %1\;cmp%d4\\t%2, %3\"},
+ {\"cmp\\t%2, %3\;cmn%d5\\t%0, #%n1\", \"cmn\\t%0, #%n1\;cmp%d4\\t%2, %3\"},
+ {\"cmn\\t%2, #%n3\;cmp%d5\\t%0, %1\", \"cmp\\t%0, %1\;cmn%d4\\t%2, #%n3\"},
+ {\"cmn\\t%2, #%n3\;cmn%d5\\t%0, #%n1\",
+ \"cmn\\t%0, #%n1\;cmn%d4\\t%2, #%n3\"}
+ };
+ int swap =
+ comparison_dominates_p (GET_CODE (operands[5]), GET_CODE (operands[4]));
+
+ return opcodes[which_alternative][swap];
+}
+"
+[(set_attr "conds" "set")
+ (set_attr "length" "8")])
+
+(define_insn "*cmp_ite1"
+ [(set (match_operand 6 "dominant_cc_register" "")
+ (compare
+ (if_then_else:SI
+ (match_operator 4 "comparison_operator"
+ [(match_operand:SI 0 "s_register_operand" "r,r,r,r")
+ (match_operand:SI 1 "arm_add_operand" "rI,L,rI,L")])
+ (match_operator:SI 5 "comparison_operator"
+ [(match_operand:SI 2 "s_register_operand" "r,r,r,r")
+ (match_operand:SI 3 "arm_add_operand" "rI,rI,L,L")])
+ (const_int 1))
+ (const_int 0)))]
+ ""
+ "*
+{
+ char* opcodes[4][2] =
+ {
+ {\"cmp\\t%0, %1\;cmp%d4\\t%2, %3\", \"cmp\\t%2, %3\;cmp%D5\\t%0, %1\"},
+ {\"cmn\\t%0, #%n1\;cmp%d4\\t%2, %3\", \"cmp\\t%2, %3\;cmn%D5\\t%0, #%n1\"},
+ {\"cmp\\t%0, %1\;cmn%d4\\t%2, #%n3\", \"cmn\\t%2, #%n3\;cmp%D5\\t%0, %1\"},
+ {\"cmn\\t%0, #%n1\;cmn%d4\\t%2, #%n3\",
+ \"cmn\\t%2, #%n3\;cmn%D5\\t%0, #%n1\"}
+ };
+ int swap =
+ comparison_dominates_p (GET_CODE (operands[5]),
+ reverse_condition (GET_CODE (operands[4])));
+
+ return opcodes[which_alternative][swap];
+}
+"
+[(set_attr "conds" "set")
+ (set_attr "length" "8")])
+
+(define_insn "*negscc"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (neg:SI (match_operator 3 "comparison_operator"
+ [(match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "arm_rhs_operand" "rI")])))
+ (clobber (reg:CC 24))]
+ ""
+ "*
+ if (GET_CODE (operands[3]) == LT && operands[3] == const0_rtx)
+ return \"mov\\t%0, %1, asr #31\";
+
+ if (GET_CODE (operands[3]) == NE)
+ return \"subs\\t%0, %1, %2\;mvnne\\t%0, #0\";
+
+ if (GET_CODE (operands[3]) == GT)
+ return \"subs\\t%0, %1, %2\;mvnne\\t%0, %0, asr #31\";
+
+ output_asm_insn (\"cmp\\t%1, %2\", operands);
+ output_asm_insn (\"mov%D3\\t%0, #0\", operands);
+ return \"mvn%d3\\t%0, #0\";
+"
+[(set_attr "conds" "clob")
+ (set_attr "length" "12")])
+
+(define_insn "movcond"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
+ (if_then_else:SI
+ (match_operator 5 "comparison_operator"
+ [(match_operand:SI 3 "s_register_operand" "r,r,r")
+ (match_operand:SI 4 "arm_add_operand" "rIL,rIL,rIL")])
+ (match_operand:SI 1 "arm_rhs_operand" "0,rI,?rI")
+ (match_operand:SI 2 "arm_rhs_operand" "rI,0,rI")))
+ (clobber (reg:CC 24))]
+ ""
+ "*
+ if (GET_CODE (operands[5]) == LT
+ && (operands[4] == const0_rtx))
+ {
+ if (which_alternative != 1 && GET_CODE (operands[1]) == REG)
+ {
+ if (operands[2] == const0_rtx)
+ return \"and\\t%0, %1, %3, asr #31\";
+ return \"ands\\t%0, %1, %3, asr #32\;movcc\\t%0, %2\";
+ }
+ else if (which_alternative != 0 && GET_CODE (operands[2]) == REG)
+ {
+ if (operands[1] == const0_rtx)
+ return \"bic\\t%0, %2, %3, asr #31\";
+ return \"bics\\t%0, %2, %3, asr #32\;movcs\\t%0, %1\";
+ }
+ /* The only case that falls through to here is when both ops 1 & 2
+ are constants */
+ }
+
+ if (GET_CODE (operands[5]) == GE
+ && (operands[4] == const0_rtx))
+ {
+ if (which_alternative != 1 && GET_CODE (operands[1]) == REG)
+ {
+ if (operands[2] == const0_rtx)
+ return \"bic\\t%0, %1, %3, asr #31\";
+ return \"bics\\t%0, %1, %3, asr #32\;movcs\\t%0, %2\";
+ }
+ else if (which_alternative != 0 && GET_CODE (operands[2]) == REG)
+ {
+ if (operands[1] == const0_rtx)
+ return \"and\\t%0, %2, %3, asr #31\";
+ return \"ands\\t%0, %2, %3, asr #32\;movcc\\t%0, %1\";
+ }
+ /* The only case that falls through to here is when both ops 1 & 2
+ are constants */
+ }
+ if (GET_CODE (operands[4]) == CONST_INT
+ && !const_ok_for_arm (INTVAL (operands[4])))
+ output_asm_insn (\"cmn\\t%3, #%n4\", operands);
+ else
+ output_asm_insn (\"cmp\\t%3, %4\", operands);
+ if (which_alternative != 0)
+ output_asm_insn (\"mov%d5\\t%0, %1\", operands);
+ if (which_alternative != 1)
+ output_asm_insn (\"mov%D5\\t%0, %2\", operands);
+ return \"\";
+"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8,8,12")])
+
+(define_insn "*ifcompare_plus_move"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (if_then_else:SI (match_operator 6 "comparison_operator"
+ [(match_operand:SI 4 "s_register_operand" "r,r")
+ (match_operand:SI 5 "arm_add_operand" "rIL,rIL")])
+ (plus:SI
+ (match_operand:SI 2 "s_register_operand" "r,r")
+ (match_operand:SI 3 "arm_add_operand" "rIL,rIL"))
+ (match_operand:SI 1 "arm_rhsm_operand" "0,?rIm")))
+ (clobber (reg:CC 24))]
+ ""
+ "#"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8,12")])
+
+(define_insn "*if_plus_move"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r,r,r")
+ (if_then_else:SI
+ (match_operator 4 "comparison_operator"
+ [(match_operand 5 "cc_register" "") (const_int 0)])
+ (plus:SI
+ (match_operand:SI 2 "s_register_operand" "r,r,r,r,r,r")
+ (match_operand:SI 3 "arm_add_operand" "rI,L,rI,L,rI,L"))
+ (match_operand:SI 1 "arm_rhsm_operand" "0,0,?rI,?rI,m,m")))]
+ ""
+ "@
+ add%d4\\t%0, %2, %3
+ sub%d4\\t%0, %2, #%n3
+ add%d4\\t%0, %2, %3\;mov%D4\\t%0, %1
+ sub%d4\\t%0, %2, #%n3\;mov%D4\\t%0, %1
+ add%d4\\t%0, %2, %3\;ldr%D4\\t%0, %1
+ sub%d4\\t%0, %2, #%n3\;ldr%D4\\t%0, %1"
+[(set_attr "conds" "use")
+ (set_attr "length" "4,4,8,8,8,8")
+ (set_attr "type" "*,*,*,*,load,load")])
+
+(define_insn "*ifcompare_move_plus"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (if_then_else:SI (match_operator 6 "comparison_operator"
+ [(match_operand:SI 4 "s_register_operand" "r,r")
+ (match_operand:SI 5 "arm_add_operand" "rIL,rIL")])
+ (match_operand:SI 1 "arm_rhsm_operand" "0,?rIm")
+ (plus:SI
+ (match_operand:SI 2 "s_register_operand" "r,r")
+ (match_operand:SI 3 "arm_add_operand" "rIL,rIL"))))
+ (clobber (reg:CC 24))]
+ ""
+ "#"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8,12")])
+
+(define_insn "*if_move_plus"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r,r,r,r,r")
+ (if_then_else:SI
+ (match_operator 4 "comparison_operator"
+ [(match_operand 5 "cc_register" "") (const_int 0)])
+ (match_operand:SI 1 "arm_rhsm_operand" "0,0,?rI,?rI,m,m")
+ (plus:SI
+ (match_operand:SI 2 "s_register_operand" "r,r,r,r,r,r")
+ (match_operand:SI 3 "arm_add_operand" "rI,L,rI,L,rI,L"))))]
+ ""
+ "@
+ add%D4\\t%0, %2, %3
+ sub%D4\\t%0, %2, #%n3
+ add%D4\\t%0, %2, %3\;mov%d4\\t%0, %1
+ sub%D4\\t%0, %2, #%n3\;mov%d4\\t%0, %1
+ add%D4\\t%0, %2, %3\;ldr%d4\\t%0, %1
+ sub%D4\\t%0, %2, #%n3\;ldr%d4\\t%0, %1"
+[(set_attr "conds" "use")
+ (set_attr "length" "4,4,8,8,8,8")
+ (set_attr "type" "*,*,*,*,load,load")])
+
+(define_insn "*ifcompare_arith_arith"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (if_then_else:SI (match_operator 9 "comparison_operator"
+ [(match_operand:SI 5 "s_register_operand" "r")
+ (match_operand:SI 6 "arm_add_operand" "rIL")])
+ (match_operator:SI 8 "shiftable_operator"
+ [(match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "arm_rhs_operand" "rI")])
+ (match_operator:SI 7 "shiftable_operator"
+ [(match_operand:SI 3 "s_register_operand" "r")
+ (match_operand:SI 4 "arm_rhs_operand" "rI")])))
+ (clobber (reg:CC 24))]
+ ""
+ "#"
+[(set_attr "conds" "clob")
+ (set_attr "length" "12")])
+
+(define_insn "*if_arith_arith"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (if_then_else:SI (match_operator 5 "comparison_operator"
+ [(match_operand 8 "cc_register" "") (const_int 0)])
+ (match_operator:SI 6 "shiftable_operator"
+ [(match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "arm_rhs_operand" "rI")])
+ (match_operator:SI 7 "shiftable_operator"
+ [(match_operand:SI 3 "s_register_operand" "r")
+ (match_operand:SI 4 "arm_rhs_operand" "rI")])))]
+ ""
+ "%I6%d5\\t%0, %1, %2\;%I7%D5\\t%0, %3, %4"
+[(set_attr "conds" "use")
+ (set_attr "length" "8")])
+
+(define_insn "*ifcompare_arith_move"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (if_then_else:SI (match_operator 6 "comparison_operator"
+ [(match_operand:SI 2 "s_register_operand" "r,r")
+ (match_operand:SI 3 "arm_add_operand" "rIL,rIL")])
+ (match_operator:SI 7 "shiftable_operator"
+ [(match_operand:SI 4 "s_register_operand" "r,r")
+ (match_operand:SI 5 "arm_rhs_operand" "rI,rI")])
+ (match_operand:SI 1 "arm_rhsm_operand" "0,?rIm")))
+ (clobber (reg:CC 24))]
+ ""
+ "*
+ /* If we have an operation where (op x 0) is the identity operation and
+ the conditional operator is LT or GE and we are comparing against zero and
+ everything is in registers then we can do this in two instructions */
+ if (operands[3] == const0_rtx
+ && GET_CODE (operands[7]) != AND
+ && GET_CODE (operands[5]) == REG
+ && GET_CODE (operands[1]) == REG
+ && REGNO (operands[1]) == REGNO (operands[4])
+ && REGNO (operands[4]) != REGNO (operands[0]))
+ {
+ if (GET_CODE (operands[6]) == LT)
+ return \"and\\t%0, %5, %2, asr #31\;%I7\\t%0, %4, %0\";
+ else if (GET_CODE (operands[6]) == GE)
+ return \"bic\\t%0, %5, %2, asr #31\;%I7\\t%0, %4, %0\";
+ }
+ if (GET_CODE (operands[3]) == CONST_INT
+ && !const_ok_for_arm (INTVAL (operands[3])))
+ output_asm_insn (\"cmn\\t%2, #%n3\", operands);
+ else
+ output_asm_insn (\"cmp\\t%2, %3\", operands);
+ output_asm_insn (\"%I7%d6\\t%0, %4, %5\", operands);
+ if (which_alternative != 0)
+ {
+ if (GET_CODE (operands[1]) == MEM)
+ return \"ldr%D6\\t%0, %1\";
+ else
+ return \"mov%D6\\t%0, %1\";
+ }
+ return \"\";
+"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8,12")])
+
+(define_insn "*if_arith_move"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
+ (if_then_else:SI (match_operator 4 "comparison_operator"
+ [(match_operand 6 "cc_register" "") (const_int 0)])
+ (match_operator:SI 5 "shiftable_operator"
+ [(match_operand:SI 2 "s_register_operand" "r,r,r")
+ (match_operand:SI 3 "arm_rhs_operand" "rI,rI,rI")])
+ (match_operand:SI 1 "arm_rhsm_operand" "0,?rI,m")))]
+ ""
+ "@
+ %I5%d4\\t%0, %2, %3
+ %I5%d4\\t%0, %2, %3\;mov%D4\\t%0, %1
+ %I5%d4\\t%0, %2, %3\;ldr%D4\\t%0, %1"
+[(set_attr "conds" "use")
+ (set_attr "length" "4,8,8")
+ (set_attr "type" "*,*,load")])
+
+(define_insn "*ifcompare_move_arith"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (if_then_else:SI (match_operator 6 "comparison_operator"
+ [(match_operand:SI 4 "s_register_operand" "r,r")
+ (match_operand:SI 5 "arm_add_operand" "rIL,rIL")])
+ (match_operand:SI 1 "arm_rhsm_operand" "0,?rIm")
+ (match_operator:SI 7 "shiftable_operator"
+ [(match_operand:SI 2 "s_register_operand" "r,r")
+ (match_operand:SI 3 "arm_rhs_operand" "rI,rI")])))
+ (clobber (reg:CC 24))]
+ ""
+ "*
+ /* If we have an operation where (op x 0) is the identity operation and
+ the conditional operator is LT or GE and we are comparing against zero and
+ everything is in registers then we can do this in two instructions */
+ if (operands[5] == const0_rtx
+ && GET_CODE (operands[7]) != AND
+ && GET_CODE (operands[3]) == REG
+ && GET_CODE (operands[1]) == REG
+ && REGNO (operands[1]) == REGNO (operands[2])
+ && REGNO (operands[2]) != REGNO (operands[0]))
+ {
+ if (GET_CODE (operands[6]) == GE)
+ return \"and\\t%0, %3, %4, asr #31\;%I7\\t%0, %2, %0\";
+ else if (GET_CODE (operands[6]) == LT)
+ return \"bic\\t%0, %3, %4, asr #31\;%I7\\t%0, %2, %0\";
+ }
+
+ if (GET_CODE (operands[5]) == CONST_INT
+ && !const_ok_for_arm (INTVAL (operands[5])))
+ output_asm_insn (\"cmn\\t%4, #%n5\", operands);
+ else
+ output_asm_insn (\"cmp\\t%4, %5\", operands);
+
+ if (which_alternative != 0)
+ {
+ if (GET_CODE (operands[1]) == MEM)
+ output_asm_insn (\"ldr%d6\\t%0, %1\", operands);
+ else
+ output_asm_insn (\"mov%d6\\t%0, %1\", operands);
+ }
+ return \"%I7%D6\\t%0, %2, %3\";
+"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8,12")])
+
+(define_insn "*if_move_arith"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
+ (if_then_else:SI
+ (match_operator 4 "comparison_operator"
+ [(match_operand 6 "cc_register" "") (const_int 0)])
+ (match_operand:SI 1 "arm_rhsm_operand" "0,?rI,m")
+ (match_operator:SI 5 "shiftable_operator"
+ [(match_operand:SI 2 "s_register_operand" "r,r,r")
+ (match_operand:SI 3 "arm_rhs_operand" "rI,rI,rI")])))]
+ ""
+ "@
+ %I5%D4\\t%0, %2, %3
+ %I5%D4\\t%0, %2, %3\;mov%d4\\t%0, %1
+ %I5%D4\\t%0, %2, %3\;ldr%d4\\t%0, %1"
+[(set_attr "conds" "use")
+ (set_attr "length" "4,8,8")
+ (set_attr "type" "*,*,load")])
+
+(define_insn "*ifcompare_move_not"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (if_then_else:SI
+ (match_operator 5 "comparison_operator"
+ [(match_operand:SI 3 "s_register_operand" "r,r")
+ (match_operand:SI 4 "arm_add_operand" "rIL,rIL")])
+ (match_operand:SI 1 "arm_not_operand" "0,?rIK")
+ (not:SI
+ (match_operand:SI 2 "s_register_operand" "r,r"))))
+ (clobber (reg:CC 24))]
+ ""
+ "#"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8,12")])
+
+(define_insn "*if_move_not"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
+ (if_then_else:SI
+ (match_operator 4 "comparison_operator"
+ [(match_operand 3 "cc_register" "") (const_int 0)])
+ (match_operand:SI 1 "arm_not_operand" "0,?rI,K")
+ (not:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))))]
+ ""
+ "@
+ mvn%D4\\t%0, %2
+ mov%d4\\t%0, %1\;mvn%D4\\t%0, %2
+ mvn%d4\\t%0, #%B1\;mvn%D4\\t%0, %2"
+[(set_attr "conds" "use")
+ (set_attr "length" "4,8,8")])
+
+(define_insn "*ifcompare_not_move"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (if_then_else:SI
+ (match_operator 5 "comparison_operator"
+ [(match_operand:SI 3 "s_register_operand" "r,r")
+ (match_operand:SI 4 "arm_add_operand" "rIL,rIL")])
+ (not:SI
+ (match_operand:SI 2 "s_register_operand" "r,r"))
+ (match_operand:SI 1 "arm_not_operand" "0,?rIK")))
+ (clobber (reg:CC 24))]
+ ""
+ "#"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8,12")])
+
+(define_insn "*if_not_move"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
+ (if_then_else:SI
+ (match_operator 4 "comparison_operator"
+ [(match_operand 3 "cc_register" "") (const_int 0)])
+ (not:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))
+ (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))]
+ ""
+ "@
+ mvn%d4\\t%0, %2
+ mov%D4\\t%0, %1\;mvn%d4\\t%0, %2
+ mvn%D4\\t%0, #%B1\;mvn%d4\\t%0, %2"
+[(set_attr "conds" "use")
+ (set_attr "length" "4,8,8")])
+
+(define_insn "*ifcompare_shift_move"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (if_then_else:SI
+ (match_operator 6 "comparison_operator"
+ [(match_operand:SI 4 "s_register_operand" "r,r")
+ (match_operand:SI 5 "arm_add_operand" "rIL,rIL")])
+ (match_operator:SI 7 "shift_operator"
+ [(match_operand:SI 2 "s_register_operand" "r,r")
+ (match_operand:SI 3 "arm_rhs_operand" "rM,rM")])
+ (match_operand:SI 1 "arm_not_operand" "0,?rIK")))
+ (clobber (reg:CC 24))]
+ ""
+ "#"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8,12")])
+
+(define_insn "*if_shift_move"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
+ (if_then_else:SI
+ (match_operator 5 "comparison_operator"
+ [(match_operand 6 "cc_register" "") (const_int 0)])
+ (match_operator:SI 4 "shift_operator"
+ [(match_operand:SI 2 "s_register_operand" "r,r,r")
+ (match_operand:SI 3 "arm_rhs_operand" "rM,rM,rM")])
+ (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))]
+ ""
+ "@
+ mov%d5\\t%0, %2%S4
+ mov%D5\\t%0, %1\;mov%d5\\t%0, %2%S4
+ mvn%D5\\t%0, #%B1\;mov%d5\\t%0, %2%S4"
+[(set_attr "conds" "use")
+ (set_attr "length" "4,8,8")])
+
+(define_insn "*ifcompare_move_shift"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (if_then_else:SI
+ (match_operator 6 "comparison_operator"
+ [(match_operand:SI 4 "s_register_operand" "r,r")
+ (match_operand:SI 5 "arm_add_operand" "rIL,rIL")])
+ (match_operand:SI 1 "arm_not_operand" "0,?rIK")
+ (match_operator:SI 7 "shift_operator"
+ [(match_operand:SI 2 "s_register_operand" "r,r")
+ (match_operand:SI 3 "arm_rhs_operand" "rM,rM")])))
+ (clobber (reg:CC 24))]
+ ""
+ "#"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8,12")])
+
+(define_insn "*if_move_shift"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
+ (if_then_else:SI
+ (match_operator 5 "comparison_operator"
+ [(match_operand 6 "cc_register" "") (const_int 0)])
+ (match_operand:SI 1 "arm_not_operand" "0,?rI,K")
+ (match_operator:SI 4 "shift_operator"
+ [(match_operand:SI 2 "s_register_operand" "r,r,r")
+ (match_operand:SI 3 "arm_rhs_operand" "rM,rM,rM")])))]
+ ""
+ "@
+ mov%D5\\t%0, %2%S4
+ mov%d5\\t%0, %1\;mov%D5\\t%0, %2%S4
+ mvn%d5\\t%0, #%B1\;mov%D5\\t%0, %2%S4"
+[(set_attr "conds" "use")
+ (set_attr "length" "4,8,8")])
+
+(define_insn "*ifcompare_shift_shift"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (if_then_else:SI
+ (match_operator 7 "comparison_operator"
+ [(match_operand:SI 5 "s_register_operand" "r")
+ (match_operand:SI 6 "arm_add_operand" "rIL")])
+ (match_operator:SI 8 "shift_operator"
+ [(match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "arm_rhs_operand" "rM")])
+ (match_operator:SI 9 "shift_operator"
+ [(match_operand:SI 3 "s_register_operand" "r")
+ (match_operand:SI 4 "arm_rhs_operand" "rM")])))
+ (clobber (reg:CC 24))]
+ ""
+ "#"
+[(set_attr "conds" "clob")
+ (set_attr "length" "12")])
+
+(define_insn "*if_shift_shift"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (if_then_else:SI
+ (match_operator 5 "comparison_operator"
+ [(match_operand 8 "cc_register" "") (const_int 0)])
+ (match_operator:SI 6 "shift_operator"
+ [(match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "arm_rhs_operand" "rM")])
+ (match_operator:SI 7 "shift_operator"
+ [(match_operand:SI 3 "s_register_operand" "r")
+ (match_operand:SI 4 "arm_rhs_operand" "rM")])))]
+ ""
+ "mov%d5\\t%0, %1%S6\;mov%D5\\t%0, %3%S7"
+[(set_attr "conds" "use")
+ (set_attr "length" "8")])
+
+(define_insn "*ifcompare_not_arith"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (if_then_else:SI
+ (match_operator 6 "comparison_operator"
+ [(match_operand:SI 4 "s_register_operand" "r")
+ (match_operand:SI 5 "arm_add_operand" "rIL")])
+ (not:SI (match_operand:SI 1 "s_register_operand" "r"))
+ (match_operator:SI 7 "shiftable_operator"
+ [(match_operand:SI 2 "s_register_operand" "r")
+ (match_operand:SI 3 "arm_rhs_operand" "rI")])))
+ (clobber (reg:CC 24))]
+ ""
+ "#"
+[(set_attr "conds" "clob")
+ (set_attr "length" "12")])
+
+(define_insn "*if_not_arith"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (if_then_else:SI
+ (match_operator 5 "comparison_operator"
+ [(match_operand 4 "cc_register" "") (const_int 0)])
+ (not:SI (match_operand:SI 1 "s_register_operand" "r"))
+ (match_operator:SI 6 "shiftable_operator"
+ [(match_operand:SI 2 "s_register_operand" "r")
+ (match_operand:SI 3 "arm_rhs_operand" "rI")])))]
+ ""
+ "mvn%d5\\t%0, %1\;%I6%D5\\t%0, %2, %3"
+[(set_attr "conds" "use")
+ (set_attr "length" "8")])
+
+(define_insn "*ifcompare_arith_not"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (if_then_else:SI
+ (match_operator 6 "comparison_operator"
+ [(match_operand:SI 4 "s_register_operand" "r")
+ (match_operand:SI 5 "arm_add_operand" "rIL")])
+ (match_operator:SI 7 "shiftable_operator"
+ [(match_operand:SI 2 "s_register_operand" "r")
+ (match_operand:SI 3 "arm_rhs_operand" "rI")])
+ (not:SI (match_operand:SI 1 "s_register_operand" "r"))))
+ (clobber (reg:CC 24))]
+ ""
+ "#"
+[(set_attr "conds" "clob")
+ (set_attr "length" "12")])
+
+(define_insn "*if_arith_not"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (if_then_else:SI
+ (match_operator 5 "comparison_operator"
+ [(match_operand 4 "cc_register" "") (const_int 0)])
+ (match_operator:SI 6 "shiftable_operator"
+ [(match_operand:SI 2 "s_register_operand" "r")
+ (match_operand:SI 3 "arm_rhs_operand" "rI")])
+ (not:SI (match_operand:SI 1 "s_register_operand" "r"))))]
+ ""
+ "mvn%D5\\t%0, %1\;%I6%d5\\t%0, %2, %3"
+[(set_attr "conds" "use")
+ (set_attr "length" "8")])
+
+(define_insn "*ifcompare_neg_move"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (if_then_else:SI
+ (match_operator 5 "comparison_operator"
+ [(match_operand:SI 3 "s_register_operand" "r,r")
+ (match_operand:SI 4 "arm_add_operand" "rIL,rIL")])
+ (neg:SI (match_operand:SI 2 "s_register_operand" "r,r"))
+ (match_operand:SI 1 "arm_not_operand" "0,?rIK")))
+ (clobber (reg:CC 24))]
+ ""
+ "#"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8,12")])
+
+(define_insn "*if_neg_move"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
+ (if_then_else:SI
+ (match_operator 4 "comparison_operator"
+ [(match_operand 3 "cc_register" "") (const_int 0)])
+ (neg:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))
+ (match_operand:SI 1 "arm_not_operand" "0,?rI,K")))]
+ ""
+ "@
+ rsb%d4\\t%0, %2, #0
+ mov%D4\\t%0, %1\;rsb%d4\\t%0, %2, #0
+ mvn%D4\\t%0, #%B1\;rsb%d4\\t%0, %2, #0"
+[(set_attr "conds" "use")
+ (set_attr "length" "4,8,8")])
+
+(define_insn "*ifcompare_move_neg"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (if_then_else:SI
+ (match_operator 5 "comparison_operator"
+ [(match_operand:SI 3 "s_register_operand" "r,r")
+ (match_operand:SI 4 "arm_add_operand" "rIL,rIL")])
+ (match_operand:SI 1 "arm_not_operand" "0,?rIK")
+ (neg:SI (match_operand:SI 2 "s_register_operand" "r,r"))))
+ (clobber (reg:CC 24))]
+ ""
+ "#"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8,12")])
+
+(define_insn "*if_move_neg"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r,r")
+ (if_then_else:SI
+ (match_operator 4 "comparison_operator"
+ [(match_operand 3 "cc_register" "") (const_int 0)])
+ (match_operand:SI 1 "arm_not_operand" "0,?rI,K")
+ (neg:SI (match_operand:SI 2 "s_register_operand" "r,r,r"))))]
+ ""
+ "@
+ rsb%D4\\t%0, %2, #0
+ mov%d4\\t%0, %1\;rsb%D4\\t%0, %2, #0
+ mvn%d4\\t%0, #%B1\;rsb%D4\\t%0, %2, #0"
+[(set_attr "conds" "use")
+ (set_attr "length" "4,8,8")])
+
+(define_insn "*arith_adjacentmem"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (match_operator:SI 1 "shiftable_operator"
+ [(match_operand:SI 2 "memory_operand" "m")
+ (match_operand:SI 3 "memory_operand" "m")]))
+ (clobber (match_scratch:SI 4 "=r"))]
+ "adjacent_mem_locations (operands[2], operands[3])"
+ "*
+{
+ rtx ldm[3];
+ rtx arith[4];
+ int val1 = 0, val2 = 0;
+
+ if (REGNO (operands[0]) > REGNO (operands[4]))
+ {
+ ldm[1] = operands[4];
+ ldm[2] = operands[0];
+ }
+ else
+ {
+ ldm[1] = operands[0];
+ ldm[2] = operands[4];
+ }
+ if (GET_CODE (XEXP (operands[2], 0)) != REG)
+ val1 = INTVAL (XEXP (XEXP (operands[2], 0), 1));
+ if (GET_CODE (XEXP (operands[3], 0)) != REG)
+ val2 = INTVAL (XEXP (XEXP (operands[3], 0), 1));
+ arith[0] = operands[0];
+ arith[3] = operands[1];
+ if (val1 < val2)
+ {
+ arith[1] = ldm[1];
+ arith[2] = ldm[2];
+ }
+ else
+ {
+ arith[1] = ldm[2];
+ arith[2] = ldm[1];
+ }
+ if (val1 && val2)
+ {
+ rtx ops[3];
+ ldm[0] = ops[0] = operands[4];
+ ops[1] = XEXP (XEXP (operands[2], 0), 0);
+ ops[2] = XEXP (XEXP (operands[2], 0), 1);
+ output_add_immediate (ops);
+ if (val1 < val2)
+ output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm);
+ else
+ output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm);
+ }
+ else if (val1)
+ {
+ ldm[0] = XEXP (operands[3], 0);
+ if (val1 < val2)
+ output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm);
+ else
+ output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm);
+ }
+ else
+ {
+ ldm[0] = XEXP (operands[2], 0);
+ if (val1 < val2)
+ output_asm_insn (\"ldm%?ia\\t%0, {%1, %2}\", ldm);
+ else
+ output_asm_insn (\"ldm%?da\\t%0, {%1, %2}\", ldm);
+ }
+ output_asm_insn (\"%I3%?\\t%0, %1, %2\", arith);
+ return \"\";
+}
+"
+[(set_attr "length" "12")
+ (set_attr "type" "load")])
+
+;; the arm can support extended pre-inc instructions
+
+;; In all these cases, we use operands 0 and 1 for the register being
+;; incremented because those are the operands that local-alloc will
+;; tie and these are the pair most likely to be tieable (and the ones
+;; that will benefit the most).
+
+;; We reject the frame pointer if it occurs anywhere in these patterns since
+;; elimination will cause too many headaches.
+
+(define_insn "*strqi_preinc"
+ [(set (mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
+ (match_operand:SI 2 "index_operand" "rJ")))
+ (match_operand:QI 3 "s_register_operand" "r"))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "REGNO (operands[0]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[1]) != FRAME_POINTER_REGNUM
+ && (GET_CODE (operands[2]) != REG
+ || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
+ "str%?b\\t%3, [%0, %2]!"
+[(set_attr "type" "store1")])
+
+(define_insn "*strqi_predec"
+ [(set (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
+ (match_operand:SI 2 "s_register_operand" "r")))
+ (match_operand:QI 3 "s_register_operand" "r"))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (minus:SI (match_dup 1) (match_dup 2)))]
+ "REGNO (operands[0]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[1]) != FRAME_POINTER_REGNUM
+ && (GET_CODE (operands[2]) != REG
+ || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
+ "str%?b\\t%3, [%0, -%2]!"
+[(set_attr "type" "store1")])
+
+(define_insn "*loadqi_preinc"
+ [(set (match_operand:QI 3 "s_register_operand" "=r")
+ (mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
+ (match_operand:SI 2 "index_operand" "rJ"))))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "REGNO (operands[0]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[1]) != FRAME_POINTER_REGNUM
+ && (GET_CODE (operands[2]) != REG
+ || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
+ "ldr%?b\\t%3, [%0, %2]!"
+[(set_attr "type" "load")])
+
+(define_insn "*loadqi_predec"
+ [(set (match_operand:QI 3 "s_register_operand" "=r")
+ (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
+ (match_operand:SI 2 "s_register_operand" "r"))))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (minus:SI (match_dup 1) (match_dup 2)))]
+ "REGNO (operands[0]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[1]) != FRAME_POINTER_REGNUM
+ && (GET_CODE (operands[2]) != REG
+ || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
+ "ldr%?b\\t%3, [%0, -%2]!"
+[(set_attr "type" "load")])
+
+(define_insn "*loadqisi_preinc"
+ [(set (match_operand:SI 3 "s_register_operand" "=r")
+ (zero_extend:SI
+ (mem:QI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
+ (match_operand:SI 2 "index_operand" "rJ")))))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "REGNO (operands[0]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[1]) != FRAME_POINTER_REGNUM
+ && (GET_CODE (operands[2]) != REG
+ || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
+ "ldr%?b\\t%3, [%0, %2]!\\t%@ z_extendqisi"
+[(set_attr "type" "load")])
+
+(define_insn "*loadqisi_predec"
+ [(set (match_operand:SI 3 "s_register_operand" "=r")
+ (zero_extend:SI
+ (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
+ (match_operand:SI 2 "s_register_operand" "r")))))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (minus:SI (match_dup 1) (match_dup 2)))]
+ "REGNO (operands[0]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[1]) != FRAME_POINTER_REGNUM
+ && (GET_CODE (operands[2]) != REG
+ || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
+ "ldr%?b\\t%3, [%0, -%2]!\\t%@ z_extendqisi"
+[(set_attr "type" "load")])
+
+(define_insn "*strsi_preinc"
+ [(set (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
+ (match_operand:SI 2 "index_operand" "rJ")))
+ (match_operand:SI 3 "s_register_operand" "r"))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "REGNO (operands[0]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[1]) != FRAME_POINTER_REGNUM
+ && (GET_CODE (operands[2]) != REG
+ || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
+ "str%?\\t%3, [%0, %2]!"
+[(set_attr "type" "store1")])
+
+(define_insn "*strqi_predec"
+ [(set (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
+ (match_operand:SI 2 "s_register_operand" "r")))
+ (match_operand:SI 3 "s_register_operand" "r"))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (minus:SI (match_dup 1) (match_dup 2)))]
+ "REGNO (operands[0]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[1]) != FRAME_POINTER_REGNUM
+ && (GET_CODE (operands[2]) != REG
+ || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
+ "str%?\\t%3, [%0, -%2]!"
+[(set_attr "type" "store1")])
+
+(define_insn "*loadsi_preinc"
+ [(set (match_operand:SI 3 "s_register_operand" "=r")
+ (mem:SI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
+ (match_operand:SI 2 "index_operand" "rJ"))))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "REGNO (operands[0]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[1]) != FRAME_POINTER_REGNUM
+ && (GET_CODE (operands[2]) != REG
+ || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
+ "ldr%?\\t%3, [%0, %2]!"
+[(set_attr "type" "load")])
+
+(define_insn "*loadsi_predec"
+ [(set (match_operand:SI 3 "s_register_operand" "=r")
+ (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
+ (match_operand:SI 2 "s_register_operand" "r"))))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (minus:SI (match_dup 1) (match_dup 2)))]
+ "REGNO (operands[0]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[1]) != FRAME_POINTER_REGNUM
+ && (GET_CODE (operands[2]) != REG
+ || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
+ "ldr%?\\t%3, [%0, -%2]!"
+[(set_attr "type" "load")])
+
+(define_insn "*loadhi_preinc"
+ [(set (match_operand:HI 3 "s_register_operand" "=r")
+ (mem:HI (plus:SI (match_operand:SI 1 "s_register_operand" "%0")
+ (match_operand:SI 2 "index_operand" "rJ"))))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ "(! BYTES_BIG_ENDIAN)
+ && ! TARGET_SHORT_BY_BYTES
+ && REGNO (operands[0]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[1]) != FRAME_POINTER_REGNUM
+ && (GET_CODE (operands[2]) != REG
+ || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
+ "ldr%?\\t%3, [%0, %2]!\\t%@ loadhi"
+[(set_attr "type" "load")])
+
+(define_insn "*loadhi_predec"
+ [(set (match_operand:HI 3 "s_register_operand" "=r")
+ (mem:HI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
+ (match_operand:SI 2 "s_register_operand" "r"))))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (minus:SI (match_dup 1) (match_dup 2)))]
+ "(!BYTES_BIG_ENDIAN)
+ && ! TARGET_SHORT_BY_BYTES
+ && REGNO (operands[0]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[1]) != FRAME_POINTER_REGNUM
+ && (GET_CODE (operands[2]) != REG
+ || REGNO (operands[2]) != FRAME_POINTER_REGNUM)"
+ "ldr%?\\t%3, [%0, -%2]!\\t%@ loadhi"
+[(set_attr "type" "load")])
+
+(define_insn "*strqi_shiftpreinc"
+ [(set (mem:QI (plus:SI (match_operator:SI 2 "shift_operator"
+ [(match_operand:SI 3 "s_register_operand" "r")
+ (match_operand:SI 4 "const_shift_operand" "n")])
+ (match_operand:SI 1 "s_register_operand" "0")))
+ (match_operand:QI 5 "s_register_operand" "r"))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)])
+ (match_dup 1)))]
+ "REGNO (operands[0]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[1]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
+ "str%?b\\t%5, [%0, %3%S2]!"
+[(set_attr "type" "store1")])
+
+(define_insn "*strqi_shiftpredec"
+ [(set (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
+ (match_operator:SI 2 "shift_operator"
+ [(match_operand:SI 3 "s_register_operand" "r")
+ (match_operand:SI 4 "const_shift_operand" "n")])))
+ (match_operand:QI 5 "s_register_operand" "r"))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3)
+ (match_dup 4)])))]
+ "REGNO (operands[0]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[1]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
+ "str%?b\\t%5, [%0, -%3%S2]!"
+[(set_attr "type" "store1")])
+
+(define_insn "*loadqi_shiftpreinc"
+ [(set (match_operand:QI 5 "s_register_operand" "=r")
+ (mem:QI (plus:SI (match_operator:SI 2 "shift_operator"
+ [(match_operand:SI 3 "s_register_operand" "r")
+ (match_operand:SI 4 "const_shift_operand" "n")])
+ (match_operand:SI 1 "s_register_operand" "0"))))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)])
+ (match_dup 1)))]
+ "REGNO (operands[0]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[1]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
+ "ldr%?b\\t%5, [%0, %3%S2]!"
+[(set_attr "type" "load")])
+
+(define_insn "*loadqi_shiftpredec"
+ [(set (match_operand:QI 5 "s_register_operand" "=r")
+ (mem:QI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
+ (match_operator:SI 2 "shift_operator"
+ [(match_operand:SI 3 "s_register_operand" "r")
+ (match_operand:SI 4 "const_shift_operand" "n")]))))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3)
+ (match_dup 4)])))]
+ "REGNO (operands[0]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[1]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
+ "ldr%?b\\t%5, [%0, -%3%S2]!"
+[(set_attr "type" "load")])
+
+(define_insn "*strsi_shiftpreinc"
+ [(set (mem:SI (plus:SI (match_operator:SI 2 "shift_operator"
+ [(match_operand:SI 3 "s_register_operand" "r")
+ (match_operand:SI 4 "const_shift_operand" "n")])
+ (match_operand:SI 1 "s_register_operand" "0")))
+ (match_operand:SI 5 "s_register_operand" "r"))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)])
+ (match_dup 1)))]
+ "REGNO (operands[0]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[1]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
+ "str%?\\t%5, [%0, %3%S2]!"
+[(set_attr "type" "store1")])
+
+(define_insn "*strsi_shiftpredec"
+ [(set (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
+ (match_operator:SI 2 "shift_operator"
+ [(match_operand:SI 3 "s_register_operand" "r")
+ (match_operand:SI 4 "const_shift_operand" "n")])))
+ (match_operand:SI 5 "s_register_operand" "r"))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3)
+ (match_dup 4)])))]
+ "REGNO (operands[0]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[1]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
+ "str%?\\t%5, [%0, -%3%S2]!"
+[(set_attr "type" "store1")])
+
+(define_insn "*loadqi_shiftpreinc"
+ [(set (match_operand:SI 5 "s_register_operand" "=r")
+ (mem:SI (plus:SI (match_operator:SI 2 "shift_operator"
+ [(match_operand:SI 3 "s_register_operand" "r")
+ (match_operand:SI 4 "const_shift_operand" "n")])
+ (match_operand:SI 1 "s_register_operand" "0"))))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)])
+ (match_dup 1)))]
+ "REGNO (operands[0]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[1]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
+ "ldr%?\\t%5, [%0, %3%S2]!"
+[(set_attr "type" "load")])
+
+(define_insn "*loadqi_shiftpredec"
+ [(set (match_operand:SI 5 "s_register_operand" "=r")
+ (mem:SI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
+ (match_operator:SI 2 "shift_operator"
+ [(match_operand:SI 3 "s_register_operand" "r")
+ (match_operand:SI 4 "const_shift_operand" "n")]))))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3)
+ (match_dup 4)])))]
+ "REGNO (operands[0]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[1]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
+ "ldr%?\\t%5, [%0, -%3%S2]!"
+[(set_attr "type" "load")])
+
+(define_insn "*loadhi_shiftpreinc"
+ [(set (match_operand:HI 5 "s_register_operand" "=r")
+ (mem:HI (plus:SI (match_operator:SI 2 "shift_operator"
+ [(match_operand:SI 3 "s_register_operand" "r")
+ (match_operand:SI 4 "const_shift_operand" "n")])
+ (match_operand:SI 1 "s_register_operand" "0"))))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (plus:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)])
+ (match_dup 1)))]
+ "(! BYTES_BIG_ENDIAN)
+ && ! TARGET_SHORT_BY_BYTES
+ && REGNO (operands[0]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[1]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
+ "ldr%?\\t%5, [%0, %3%S2]!\\t%@ loadhi"
+[(set_attr "type" "load")])
+
+(define_insn "*loadhi_shiftpredec"
+ [(set (match_operand:HI 5 "s_register_operand" "=r")
+ (mem:HI (minus:SI (match_operand:SI 1 "s_register_operand" "0")
+ (match_operator:SI 2 "shift_operator"
+ [(match_operand:SI 3 "s_register_operand" "r")
+ (match_operand:SI 4 "const_shift_operand" "n")]))))
+ (set (match_operand:SI 0 "s_register_operand" "=r")
+ (minus:SI (match_dup 1) (match_op_dup 2 [(match_dup 3)
+ (match_dup 4)])))]
+ "(! BYTES_BIG_ENDIAN)
+ && ! TARGET_SHORT_BY_BYTES
+ && REGNO (operands[0]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[1]) != FRAME_POINTER_REGNUM
+ && REGNO (operands[3]) != FRAME_POINTER_REGNUM"
+ "ldr%?\\t%5, [%0, -%3%S2]!\\t%@ loadhi"
+[(set_attr "type" "load")])
+
+; It can also support extended post-inc expressions, but combine doesn't
+; try these....
+; It doesn't seem worth adding peepholes for anything but the most common
+; cases since, unlike combine, the increment must immediately follow the load
+; for this pattern to match.
+; When loading we must watch to see that the base register isn't trampled by
+; the load. In such cases this isn't a post-inc expression.
+
+(define_peephole
+ [(set (mem:QI (match_operand:SI 0 "s_register_operand" "+r"))
+ (match_operand:QI 2 "s_register_operand" "r"))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0) (match_operand:SI 1 "index_operand" "rJ")))]
+ ""
+ "str%?b\\t%2, [%0], %1")
+
+(define_peephole
+ [(set (match_operand:QI 0 "s_register_operand" "=r")
+ (mem:QI (match_operand:SI 1 "s_register_operand" "+r")))
+ (set (match_dup 1)
+ (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))]
+ "REGNO(operands[0]) != REGNO(operands[1])
+ && (GET_CODE (operands[2]) != REG
+ || REGNO(operands[0]) != REGNO (operands[2]))"
+ "ldr%?b\\t%0, [%1], %2")
+
+(define_peephole
+ [(set (mem:SI (match_operand:SI 0 "s_register_operand" "+r"))
+ (match_operand:SI 2 "s_register_operand" "r"))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0) (match_operand:SI 1 "index_operand" "rJ")))]
+ ""
+ "str%?\\t%2, [%0], %1")
+
+(define_peephole
+ [(set (match_operand:HI 0 "s_register_operand" "=r")
+ (mem:HI (match_operand:SI 1 "s_register_operand" "+r")))
+ (set (match_dup 1)
+ (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))]
+ "(! BYTES_BIG_ENDIAN)
+ && ! TARGET_SHORT_BY_BYTES
+ && REGNO(operands[0]) != REGNO(operands[1])
+ && (GET_CODE (operands[2]) != REG
+ || REGNO(operands[0]) != REGNO (operands[2]))"
+ "ldr%?\\t%0, [%1], %2\\t%@ loadhi")
+
+(define_peephole
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (mem:SI (match_operand:SI 1 "s_register_operand" "+r")))
+ (set (match_dup 1)
+ (plus:SI (match_dup 1) (match_operand:SI 2 "index_operand" "rJ")))]
+ "REGNO(operands[0]) != REGNO(operands[1])
+ && (GET_CODE (operands[2]) != REG
+ || REGNO(operands[0]) != REGNO (operands[2]))"
+ "ldr%?\\t%0, [%1], %2")
+
+(define_peephole
+ [(set (mem:QI (plus:SI (match_operand:SI 0 "s_register_operand" "+r")
+ (match_operand:SI 1 "index_operand" "rJ")))
+ (match_operand:QI 2 "s_register_operand" "r"))
+ (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))]
+ ""
+ "str%?b\\t%2, [%0, %1]!")
+
+(define_peephole
+ [(set (mem:QI (plus:SI (match_operator:SI 4 "shift_operator"
+ [(match_operand:SI 0 "s_register_operand" "r")
+ (match_operand:SI 1 "const_int_operand" "n")])
+ (match_operand:SI 2 "s_register_operand" "+r")))
+ (match_operand:QI 3 "s_register_operand" "r"))
+ (set (match_dup 2) (plus:SI (match_op_dup 4 [(match_dup 0) (match_dup 1)])
+ (match_dup 2)))]
+ ""
+ "str%?b\\t%3, [%2, %0%S4]!")
+
+; This pattern is never tried by combine, so do it as a peephole
+
+(define_peephole
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (match_operand:SI 1 "s_register_operand" "r"))
+ (set (reg:CC 24)
+ (compare:CC (match_dup 1) (const_int 0)))]
+ ""
+ "sub%?s\\t%0, %1, #0"
+[(set_attr "conds" "set")])
+
+; Peepholes to spot possible load- and store-multiples, if the ordering is
+; reversed, check that the memory references aren't volatile.
+
+(define_peephole
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (match_operand:SI 4 "memory_operand" "m"))
+ (set (match_operand:SI 1 "s_register_operand" "=r")
+ (match_operand:SI 5 "memory_operand" "m"))
+ (set (match_operand:SI 2 "s_register_operand" "=r")
+ (match_operand:SI 6 "memory_operand" "m"))
+ (set (match_operand:SI 3 "s_register_operand" "=r")
+ (match_operand:SI 7 "memory_operand" "m"))]
+ "load_multiple_sequence (operands, 4, NULL, NULL, NULL)"
+ "*
+ return emit_ldm_seq (operands, 4);
+")
+
+(define_peephole
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (match_operand:SI 3 "memory_operand" "m"))
+ (set (match_operand:SI 1 "s_register_operand" "=r")
+ (match_operand:SI 4 "memory_operand" "m"))
+ (set (match_operand:SI 2 "s_register_operand" "=r")
+ (match_operand:SI 5 "memory_operand" "m"))]
+ "load_multiple_sequence (operands, 3, NULL, NULL, NULL)"
+ "*
+ return emit_ldm_seq (operands, 3);
+")
+
+(define_peephole
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (match_operand:SI 2 "memory_operand" "m"))
+ (set (match_operand:SI 1 "s_register_operand" "=r")
+ (match_operand:SI 3 "memory_operand" "m"))]
+ "load_multiple_sequence (operands, 2, NULL, NULL, NULL)"
+ "*
+ return emit_ldm_seq (operands, 2);
+")
+
+(define_peephole
+ [(set (match_operand:SI 4 "memory_operand" "=m")
+ (match_operand:SI 0 "s_register_operand" "r"))
+ (set (match_operand:SI 5 "memory_operand" "=m")
+ (match_operand:SI 1 "s_register_operand" "r"))
+ (set (match_operand:SI 6 "memory_operand" "=m")
+ (match_operand:SI 2 "s_register_operand" "r"))
+ (set (match_operand:SI 7 "memory_operand" "=m")
+ (match_operand:SI 3 "s_register_operand" "r"))]
+ "store_multiple_sequence (operands, 4, NULL, NULL, NULL)"
+ "*
+ return emit_stm_seq (operands, 4);
+")
+
+(define_peephole
+ [(set (match_operand:SI 3 "memory_operand" "=m")
+ (match_operand:SI 0 "s_register_operand" "r"))
+ (set (match_operand:SI 4 "memory_operand" "=m")
+ (match_operand:SI 1 "s_register_operand" "r"))
+ (set (match_operand:SI 5 "memory_operand" "=m")
+ (match_operand:SI 2 "s_register_operand" "r"))]
+ "store_multiple_sequence (operands, 3, NULL, NULL, NULL)"
+ "*
+ return emit_stm_seq (operands, 3);
+")
+
+(define_peephole
+ [(set (match_operand:SI 2 "memory_operand" "=m")
+ (match_operand:SI 0 "s_register_operand" "r"))
+ (set (match_operand:SI 3 "memory_operand" "=m")
+ (match_operand:SI 1 "s_register_operand" "r"))]
+ "store_multiple_sequence (operands, 2, NULL, NULL, NULL)"
+ "*
+ return emit_stm_seq (operands, 2);
+")
+
+;; A call followed by return can be replaced by restoring the regs and
+;; jumping to the subroutine, provided we aren't passing the address of
+;; any of our local variables. If we call alloca then this is unsafe
+;; since restoring the frame frees the memory, which is not what we want.
+;; Sometimes the return might have been targeted by the final prescan:
+;; if so then emit a proper return insn as well.
+;; Unfortunately, if the frame pointer is required, we don't know if the
+;; current function has any implicit stack pointer adjustments that will
+;; be restored by the return: we can't therefore do a tail call.
+;; Another unfortunate that we can't handle is if current_function_args_size
+;; is non-zero: in this case elimination of the argument pointer assumed
+;; that lr was pushed onto the stack, so eliminating upsets the offset
+;; calculations.
+
+(define_peephole
+ [(parallel [(call (mem:SI (match_operand:SI 0 "" "X"))
+ (match_operand:SI 1 "general_operand" "g"))
+ (clobber (reg:SI 14))])
+ (return)]
+ "(GET_CODE (operands[0]) == SYMBOL_REF && USE_RETURN_INSN (FALSE)
+ && !get_frame_size () && !current_function_calls_alloca
+ && !frame_pointer_needed && !current_function_args_size)"
+ "*
+{
+ extern rtx arm_target_insn;
+ extern int arm_ccfsm_state;
+
+ if (arm_ccfsm_state && arm_target_insn && INSN_DELETED_P (arm_target_insn))
+ {
+ arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
+ output_return_instruction (NULL, TRUE, FALSE);
+ arm_ccfsm_state = 0;
+ arm_target_insn = NULL;
+ }
+
+ output_return_instruction (NULL, FALSE, FALSE);
+ return \"b%?\\t%a0\";
+}"
+[(set_attr "type" "call")
+ (set_attr "length" "8")])
+
+(define_peephole
+ [(parallel [(set (match_operand 0 "s_register_operand" "=rf")
+ (call (mem:SI (match_operand:SI 1 "" "X"))
+ (match_operand:SI 2 "general_operand" "g")))
+ (clobber (reg:SI 14))])
+ (return)]
+ "(GET_CODE (operands[1]) == SYMBOL_REF && USE_RETURN_INSN (FALSE)
+ && !get_frame_size () && !current_function_calls_alloca
+ && !frame_pointer_needed && !current_function_args_size)"
+ "*
+{
+ extern rtx arm_target_insn;
+ extern int arm_ccfsm_state;
+
+ if (arm_ccfsm_state && arm_target_insn && INSN_DELETED_P (arm_target_insn))
+ {
+ arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
+ output_return_instruction (NULL, TRUE, FALSE);
+ arm_ccfsm_state = 0;
+ arm_target_insn = NULL;
+ }
+
+ output_return_instruction (NULL, FALSE, FALSE);
+ return \"b%?\\t%a1\";
+}"
+[(set_attr "type" "call")
+ (set_attr "length" "8")])
+
+;; As above but when this function is not void, we must be returning the
+;; result of the called subroutine.
+
+(define_peephole
+ [(parallel [(set (match_operand 0 "s_register_operand" "=rf")
+ (call (mem:SI (match_operand:SI 1 "" "X"))
+ (match_operand:SI 2 "general_operand" "g")))
+ (clobber (reg:SI 14))])
+ (use (match_dup 0))
+ (return)]
+ "(GET_CODE (operands[1]) == SYMBOL_REF && USE_RETURN_INSN (FALSE)
+ && !get_frame_size () && !current_function_calls_alloca
+ && !frame_pointer_needed && !current_function_args_size)"
+ "*
+{
+ extern rtx arm_target_insn;
+ extern int arm_ccfsm_state;
+
+ if (arm_ccfsm_state && arm_target_insn && INSN_DELETED_P (arm_target_insn))
+ {
+ arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
+ output_return_instruction (NULL, TRUE, FALSE);
+ arm_ccfsm_state = 0;
+ arm_target_insn = NULL;
+ }
+
+ output_return_instruction (NULL, FALSE, FALSE);
+ return \"b%?\\t%a1\";
+}"
+[(set_attr "type" "call")
+ (set_attr "length" "8")])
+
+;; CYGNUS LOCAL
+;; If calling a subroutine and then jumping back to somewhere else, but not
+;; too far away, then we can set the link register with the branch address
+;; and jump direct to the subroutine. On return from the subroutine
+;; execution continues at the branch; this avoids a prefetch stall.
+;; We use the length attribute (via short_branch ()) to establish whether or
+;; not this is possible, this is the same as the sparc does.
+
+(define_peephole
+ [(parallel[(call (mem:SI (match_operand:SI 0 "" "X"))
+ (match_operand:SI 1 "general_operand" "g"))
+ (clobber (reg:SI 14))])
+ (set (pc)
+ (label_ref (match_operand 2 "" "")))]
+ "0 && GET_CODE (operands[0]) == SYMBOL_REF
+ && short_branch (INSN_UID (insn), INSN_UID (operands[2]))
+ && arm_insn_not_targeted (insn)"
+ "*
+{
+ int backward = arm_backwards_branch (INSN_UID (insn),
+ INSN_UID (operands[2]));
+
+#if 0
+ /* Putting this in means that TARGET_6 code will ONLY run on an arm6 or
+ * above, leaving it out means that the code will still run on an arm 2 or 3
+ */
+ if (TARGET_6)
+ {
+ if (backward)
+ output_asm_insn (\"sub%?\\t%|lr, %|pc, #(8 + . -%l2)\", operands);
+ else
+ output_asm_insn (\"add%?\\t%|lr, %|pc, #(%l2 - . -8)\", operands);
+ }
+ else
+#endif
+ {
+ output_asm_insn (\"mov%?\\t%|lr, %|pc\\t%@ protect cc\", operands);
+ if (backward)
+ output_asm_insn (\"sub%?\\t%|lr, %|lr, #(4 + . -%l2)\", operands);
+ else
+ output_asm_insn (\"add%?\\t%|lr, %|lr, #(%l2 - . -4)\", operands);
+ }
+ return \"b%?\\t%a0\";
+}"
+[(set_attr "type" "call")
+ (set (attr "length")
+ (if_then_else (eq_attr "prog_mode" "prog32")
+ (const_int 8)
+ (const_int 12)))])
+
+(define_peephole
+ [(parallel[(set (match_operand:SI 0 "s_register_operand" "=r")
+ (call (mem:SI (match_operand:SI 1 "" "X"))
+ (match_operand:SI 2 "general_operand" "g")))
+ (clobber (reg:SI 14))])
+ (set (pc)
+ (label_ref (match_operand 3 "" "")))]
+ "0 && GET_CODE (operands[0]) == SYMBOL_REF
+ && short_branch (INSN_UID (insn), INSN_UID (operands[3]))
+ && arm_insn_not_targeted (insn)"
+ "*
+{
+ int backward = arm_backwards_branch (INSN_UID (insn),
+ INSN_UID (operands[3]));
+
+#if 0
+ /* Putting this in means that TARGET_6 code will ONLY run on an arm6 or
+ * above, leaving it out means that the code will still run on an arm 2 or 3
+ */
+ if (TARGET_6)
+ {
+ if (backward)
+ output_asm_insn (\"sub%?\\t%|lr, %|pc, #(8 + . -%l3)\", operands);
+ else
+ output_asm_insn (\"add%?\\t%|lr, %|pc, #(%l3 - . -8)\", operands);
+ }
+ else
+#endif
+ {
+ output_asm_insn (\"mov%?\\t%|lr, %|pc\\t%@ protect cc\", operands);
+ if (backward)
+ output_asm_insn (\"sub%?\\t%|lr, %|lr, #(4 + . -%l3)\", operands);
+ else
+ output_asm_insn (\"add%?\\t%|lr, %|lr, #(%l3 - . -4)\", operands);
+ }
+ return \"b%?\\t%a1\";
+}"
+[(set_attr "type" "call")
+ (set (attr "length")
+ (if_then_else (eq_attr "prog_mode" "prog32")
+ (const_int 8)
+ (const_int 12)))])
+;; END CYGNUS LOCAL
+
+(define_split
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (and:SI (ge:SI (match_operand:SI 1 "s_register_operand" "")
+ (const_int 0))
+ (neg:SI (match_operator:SI 2 "comparison_operator"
+ [(match_operand:SI 3 "s_register_operand" "")
+ (match_operand:SI 4 "arm_rhs_operand" "")]))))
+ (clobber (match_operand:SI 5 "s_register_operand" ""))]
+ ""
+ [(set (match_dup 5) (not:SI (ashiftrt:SI (match_dup 1) (const_int 31))))
+ (set (match_dup 0) (and:SI (match_op_dup 2 [(match_dup 3) (match_dup 4)])
+ (match_dup 5)))]
+ "")
+
+;; This split can be used because CC_Z mode implies that the following
+;; branch will be an equality, or an unsigned inequality, so the sign
+;; extension is not needed.
+
+(define_split
+ [(set (reg:CC_Z 24)
+ (compare:CC_Z
+ (ashift:SI (subreg:SI (match_operand:QI 0 "memory_operand" "") 0)
+ (const_int 24))
+ (match_operand 1 "const_int_operand" "")))
+ (clobber (match_scratch:SI 2 ""))]
+ "((unsigned HOST_WIDE_INT) INTVAL (operands[1]))
+ == (((unsigned HOST_WIDE_INT) INTVAL (operands[1])) >> 24) << 24"
+ [(set (match_dup 2) (zero_extend:SI (match_dup 0)))
+ (set (reg:CC 24) (compare:CC (match_dup 2) (match_dup 1)))]
+ "
+ operands[1] = GEN_INT (((unsigned long) INTVAL (operands[1])) >> 24);
+")
+
+(define_expand "prologue"
+ [(clobber (const_int 0))]
+ ""
+ "
+ arm_expand_prologue ();
+ DONE;
+")
+
+;; This split is only used during output to reduce the number of patterns
+;; that need assembler instructions adding to them. We allowed the setting
+;; of the conditions to be implicit during rtl generation so that
+;; the conditional compare patterns would work. However this conflicts to
+;; some extent with the conditional data operations, so we have to split them
+;; up again here.
+
+(define_split
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (if_then_else:SI (match_operator 1 "comparison_operator"
+ [(match_operand 2 "" "") (match_operand 3 "" "")])
+ (match_operand 4 "" "")
+ (match_operand 5 "" "")))
+ (clobber (reg:CC 24))]
+ "reload_completed"
+ [(set (match_dup 6) (match_dup 7))
+ (set (match_dup 0)
+ (if_then_else:SI (match_op_dup 1 [(match_dup 6) (const_int 0)])
+ (match_dup 4)
+ (match_dup 5)))]
+ "
+{
+ enum machine_mode mode = SELECT_CC_MODE (GET_CODE (operands[1]), operands[2],
+ operands[3]);
+
+ operands[6] = gen_rtx (REG, mode, 24);
+ operands[7] = gen_rtx (COMPARE, mode, operands[2], operands[3]);
+}
+")
+
+;; CYGNUS LOCAL
+(define_split
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (if_then_else:SI (match_operator 1 "comparison_operator"
+ [(match_operand:SI 2 "s_register_operand" "")
+ (match_operand:SI 3 "arm_add_operand" "")])
+ (match_operand:SI 4 "arm_rhs_operand" "")
+ (not:SI
+ (match_operand:SI 5 "s_register_operand" ""))))
+ (clobber (reg:CC 24))]
+ "reload_completed"
+ [(set (match_dup 6) (match_dup 7))
+ (set (match_dup 0)
+ (if_then_else:SI (match_op_dup 1 [(match_dup 6) (const_int 0)])
+ (match_dup 4)
+ (not:SI (match_dup 5))))]
+ "
+{
+ enum machine_mode mode = SELECT_CC_MODE (GET_CODE (operands[1]), operands[2],
+ operands[3]);
+
+ operands[6] = gen_rtx (REG, mode, 24);
+ operands[7] = gen_rtx (COMPARE, mode, operands[2], operands[3]);
+}
+")
+
+(define_insn "*cond_move_not"
+ [(set (match_operand:SI 0 "s_register_operand" "=r,r")
+ (if_then_else:SI (match_operator 4 "comparison_operator"
+ [(match_operand 3 "cc_register" "") (const_int 0)])
+ (match_operand:SI 1 "arm_rhs_operand" "0,?rI")
+ (not:SI
+ (match_operand:SI 2 "s_register_operand" "r,r"))))]
+ ""
+ "@
+ mvn%D4\\t%0, %2
+ mov%d4\\t%0, %1\;mvn%D4\\t%0, %2"
+[(set_attr "conds" "use")
+ (set_attr "length" "4,8")])
+;; END CYGNUS LOCAL
+
+;; The next two patterns occur when an AND operation is followed by a
+;; scc insn sequence
+
+(define_insn "*sign_extract_onebit"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (sign_extract:SI (match_operand:SI 1 "s_register_operand" "r")
+ (const_int 1)
+ (match_operand:SI 2 "const_int_operand" "n")))]
+ ""
+ "*
+ operands[2] = GEN_INT (1 << INTVAL (operands[2]));
+ output_asm_insn (\"ands\\t%0, %1, %2\", operands);
+ return \"mvnne\\t%0, #0\";
+"
+[(set_attr "conds" "clob")
+ (set_attr "length" "8")])
+
+(define_insn "*not_signextract_onebit"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (not:SI
+ (sign_extract:SI (match_operand:SI 1 "s_register_operand" "r")
+ (const_int 1)
+ (match_operand:SI 2 "const_int_operand" "n"))))]
+ ""
+ "*
+ operands[2] = GEN_INT (1 << INTVAL (operands[2]));
+ output_asm_insn (\"tst\\t%1, %2\", operands);
+ output_asm_insn (\"mvneq\\t%0, #0\", operands);
+ return \"movne\\t%0, #0\";
+"
+[(set_attr "conds" "clob")
+ (set_attr "length" "12")])
+
+;; Push multiple registers to the stack. The first register is in the
+;; unspec part of the insn; subsequent registers are in parallel (use ...)
+;; expressions.
+(define_insn "*push_multi"
+ [(match_parallel 2 "multi_register_push"
+ [(set (match_operand:BLK 0 "memory_operand" "=m")
+ (unspec:BLK [(match_operand:SI 1 "s_register_operand" "r")] 2))])]
+ ""
+ "*
+{
+ char pattern[100];
+ int i;
+ extern int lr_save_eliminated;
+
+ if (lr_save_eliminated)
+ {
+ if (XVECLEN (operands[2], 0) > 1)
+ abort ();
+ return \"\";
+ }
+ strcpy (pattern, \"stmfd\\t%m0!, {%1\");
+ for (i = 1; i < XVECLEN (operands[2], 0); i++)
+ {
+ strcat (pattern, \", %|\");
+ strcat (pattern, reg_names[REGNO (XEXP (XVECEXP (operands[2], 0, i),
+ 0))]);
+ }
+ strcat (pattern, \"}\");
+ output_asm_insn (pattern, operands);
+ return \"\";
+}"
+[(set_attr "type" "store4")])
+
+;; Similarly for the floating point registers
+(define_insn "*push_fp_multi"
+ [(match_parallel 2 "multi_register_push"
+ [(set (match_operand:BLK 0 "memory_operand" "=m")
+ (unspec:BLK [(match_operand:XF 1 "f_register_operand" "f")] 2))])]
+ ""
+ "*
+{
+ char pattern[100];
+ int i;
+
+ sprintf (pattern, \"sfmfd\\t%%1, %d, [%%m0]!\", XVECLEN (operands[2], 0));
+ output_asm_insn (pattern, operands);
+ return \"\";
+}"
+[(set_attr "type" "f_store")])
+
+;; Special patterns for dealing with the constant pool
+
+(define_insn "consttable_4"
+ [(unspec_volatile [(match_operand 0 "" "")] 2)]
+ ""
+ "*
+{
+ switch (GET_MODE_CLASS (GET_MODE (operands[0])))
+ {
+ case MODE_FLOAT:
+ {
+ union real_extract u;
+ bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u);
+ assemble_real (u.d, GET_MODE (operands[0]));
+ break;
+ }
+ default:
+ assemble_integer (operands[0], 4, 1);
+ break;
+ }
+ return \"\";
+}"
+[(set_attr "length" "4")])
+
+(define_insn "consttable_8"
+ [(unspec_volatile [(match_operand 0 "" "")] 3)]
+ ""
+ "*
+{
+ switch (GET_MODE_CLASS (GET_MODE (operands[0])))
+ {
+ case MODE_FLOAT:
+ {
+ union real_extract u;
+ bcopy ((char *) &CONST_DOUBLE_LOW (operands[0]), (char *) &u, sizeof u);
+ assemble_real (u.d, GET_MODE (operands[0]));
+ break;
+ }
+ default:
+ assemble_integer (operands[0], 8, 1);
+ break;
+ }
+ return \"\";
+}"
+[(set_attr "length" "8")])
+
+(define_insn "consttable_end"
+ [(unspec_volatile [(const_int 0)] 4)]
+ ""
+ "*
+ /* Nothing to do (currently). */
+ return \"\";
+")
+
+(define_insn "align_4"
+ [(unspec_volatile [(const_int 0)] 5)]
+ ""
+ "*
+ assemble_align (32);
+ return \"\";
+")