6489 lines
202 KiB
Markdown
6489 lines
202 KiB
Markdown
|
;;- Machine description for Advanced RISC Machines' ARM for GNU compiler
|
|||
|
;; Copyright (C) 1991, 93-98, 1999 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))])]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
(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))])]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
(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))]
|
|||
|
"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))]
|
|||
|
"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 \"\";
|
|||
|
")
|