;;- Machine description for ARM for GNU compiler
;; Copyright (C) 1991-2022 Free Software Foundation, Inc.
;; Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl)
;; and Martin Simmons (@harleqn.co.uk).
;; More major hacks by Richard Earnshaw (rearnsha@arm.com).
;; This file is part of GCC.
;; GCC is free software; you can redistribute it and/or modify it
;; under the terms of the GNU General Public License as published
;; by the Free Software Foundation; either version 3, or (at your
;; option) any later version.
;; GCC is distributed in the hope that it will be useful, but WITHOUT
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
;; License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GCC; see the file COPYING3. If not see
;; <http://www.gnu.org/licenses/>.
;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
;;---------------------------------------------------------------------------
;; Constants
;; Register numbers -- All machine registers should be defined here
(define_constants
[(R0_REGNUM 0) ; First CORE register
(R1_REGNUM 1) ; Second CORE register
(R4_REGNUM 4) ; Fifth CORE register
(FDPIC_REGNUM 9) ; FDPIC register
(IP_REGNUM 12) ; Scratch register
(SP_REGNUM 13) ; Stack pointer
(LR_REGNUM 14) ; Return address register
(PC_REGNUM 15) ; Program counter
(LAST_ARM_REGNUM 15) ;
(CC_REGNUM 100) ; Condition code pseudo register
(VFPCC_REGNUM 101) ; VFP Condition code pseudo register
(APSRQ_REGNUM 104) ; Q bit pseudo register
(APSRGE_REGNUM 105) ; GE bits pseudo register
(VPR_REGNUM 106) ; Vector Predication Register - MVE register.
]
)
;; 3rd operand to select_dominance_cc_mode
(define_constants
[(DOM_CC_X_AND_Y 0)
(DOM_CC_NX_OR_Y 1)
(DOM_CC_X_OR_Y 2)
]
)
;; conditional compare combination
(define_constants
[(CMP_CMP 0)
(CMN_CMP 1)
(CMP_CMN 2)
(CMN_CMN 3)
(NUM_OF_COND_CMP 4)
]
)
;;---------------------------------------------------------------------------
;; Attributes
;; Processor type. This is created automatically from arm-cores.def.
(include "arm-tune.md")
;; Instruction classification types
(include "types.md")
; IS_THUMB is set to 'yes' when we are generating Thumb code, and 'no' when
; generating ARM code. This is used to control the length of some insn
; patterns that share the same RTL in both ARM and Thumb code.
(define_attr "is_thumb" "yes,no"
(const (if_then_else (symbol_ref "TARGET_THUMB")
(const_string "yes") (const_string "no"))))
; IS_ARCH6 is set to 'yes' when we are generating code form ARMv6.
(define_attr "is_arch6" "no,yes" (const (symbol_ref "arm_arch6")))
; IS_THUMB1 is set to 'yes' iff we are generating Thumb-1 code.
(define_attr "is_thumb1" "yes,no"
(const (if_then_else (symbol_ref "TARGET_THUMB1")
(const_string "yes") (const_string "no"))))
; Mark an instruction as suitable for "short IT" blocks in Thumb-2.
; The arm_restrict_it flag enables the "short IT" feature which
; restricts IT blocks to a single 16-bit instruction.
; This attribute should only be used on 16-bit Thumb-2 instructions
; which may be predicated (the "predicable" attribute must be set).
(define_attr "predicable_short_it" "no,yes" (const_string "no"))
; Mark an instruction as suitable for "short IT" blocks in Thumb-2.
; This attribute should only be used on instructions which may emit
; an IT block in their expansion which is not a short IT.
(define_attr "enabled_for_short_it" "no,yes" (const_string "yes"))
; Mark an instruction sequence as the required way of loading a
; constant when -mpure-code is enabled (which implies
; arm_disable_literal_pool)
(define_attr "required_for_purecode" "no,yes" (const_string "no"))
;; Operand number of an input operand that is shifted. Zero if the
;; given instruction does not shift one of its input operands.
(define_attr "shift" "" (const_int 0))
;; [For compatibility with AArch64 in pipeline models]
;; Attribute that specifies whether or not the instruction touches fp
;; registers.
(define_attr "fp" "no,yes" (const_string "no"))
; 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" "none,vfp"
(const (symbol_ref "arm_fpu_attr")))
; Predicated means that the insn form is conditionally executed based on a
; predicate. We default to 'no' because no Thumb patterns match this rule
; and not all ARM insns do.
(define_attr "predicated" "yes,no" (const_string "no"))
; LENGTH of an instruction (in bytes)
(define_attr "length" ""
(const_int 4))
; The architecture which supports the instruction (or alternative).
; This can be "a" for ARM, "t" for either of the Thumbs, "32" for
; TARGET_32BIT, "t1" or "t2" to specify a specific Thumb mode. "v6"
; for ARM or Thumb-2 with arm_arch6, and nov6 for ARM without
; arm_arch6. "v6t2" for Thumb-2 with arm_arch6 and "v8mb" for ARMv8-M
; Baseline. "fix_vlldm" is for fixing the v8-m/v8.1-m VLLDM erratum.
; This attribute is used to compute attribute "enabled",
; use type "any" to enable an alternative in all cases.
(define_attr "arch" "any, a, t, 32, t1, t2, v6,nov6, v6t2, \
v8mb, fix_vlldm, iwmmxt, iwmmxt2, armv6_or_vfpv3, \
neon, mve"
(const_string "any"))
(define_attr "arch_enabled" "no,yes"
(cond [(eq_attr "arch" "any")
(const_string "yes")
(and (eq_attr "arch" "a")
(match_test "TARGET_ARM"))
(const_string "yes")
(and (eq_attr "arch" "t")
(match_test "TARGET_THUMB"))
(const_string "yes")
(and (eq_attr "arch" "t1")
(match_test "TARGET_THUMB1"))
(const_string "yes")
(and (eq_attr "arch" "t2")
(match_test "TARGET_THUMB2"))
(const_string "yes")
(and (eq_attr "arch" "32")
(match_test "TARGET_32BIT"))
(const_string "yes")
(and (eq_attr "arch" "v6")
(match_test "TARGET_32BIT && arm_arch6"))
(const_string "yes")
(and (eq_attr "arch" "nov6")
(match_test "TARGET_32BIT && !arm_arch6"))
(const_string "yes")
(and (eq_attr "arch" "v6t2")
(match_test "TARGET_32BIT && arm_arch6 && arm_arch_thumb2"))
(const_string "yes")
(and (eq_attr "arch" "v8mb")
(match_test "TARGET_THUMB1 && arm_arch8"))
(const_string "yes")
(and (eq_attr "arch" "fix_vlldm")
(match_test "fix_vlldm"))
(const_string "yes")
(and (eq_attr "arch" "iwmmxt2")
(match_test "TARGET_REALLY_IWMMXT2"))
(const_string "yes")
(and (eq_attr "arch" "armv6_or_vfpv3")
(match_test "arm_arch6 || TARGET_VFP3"))
(const_string "yes")
(and (eq_attr "arch" "neon")
(match_test "TARGET_NEON"))
(const_string "yes")
(and (eq_attr "arch" "mve")
(match_test "TARGET_HAVE_MVE"))
(const_string "yes")
]
(const_string "no")))
(define_attr "opt" "any,speed,size"
(const_string "any"))
(define_attr "opt_enabled" "no,yes"
(cond [(eq_attr "opt" "any")
(const_string "yes")
(and (eq_attr "opt" "speed")
(match_test "optimize_function_for_speed_p (cfun)"))
(const_string "yes")
(and (eq_attr "opt" "size")
(match_test "optimize_function_for_size_p (cfun)"))
(const_string "yes")]
(const_string "no")))
(define_attr "use_literal_pool" "no,yes"
(cond [(and (eq_attr "type" "f_loads,f_loadd")
(match_test "CONSTANT_P (operands[1])"))
(const_string "yes")]
(const_string "no")))
; Enable all alternatives that are both arch_enabled and insn_enabled.
; FIXME:: opt_enabled has been temporarily removed till the time we have
; an attribute that allows the use of such alternatives.
; This depends on caching of speed_p, size_p on a per
; alternative basis. The problem is that the enabled attribute
; cannot depend on any state that is not cached or is not constant
; for a compilation unit. We probably need a generic "hot/cold"
; alternative which if implemented can help with this. We disable this
; until such a time as this is implemented and / or the improvements or
; regressions with removing this attribute are double checked.
; See ashldi3_neon and <shift>di3_neon in neon.md.
(define_attr "enabled" "no,yes"
(cond [(and (eq_attr "predicable_short_it" "no")
(and (eq_attr "predicated" "yes")
(match_test "arm_restrict_it")))
(const_string "no")
(and (eq_attr "enabled_for_short_it" "no")
(match_test "arm_restrict_it"))
(const_string "no")
(and (eq_attr "required_for_purecode" "yes")
(not (match_test "arm_disable_literal_pool")))
(const_string "no")
(eq_attr "arch_enabled" "no")
(const_string "no")]
(const_string "yes")))
; POOL_RANGE is how far away from a constant pool entry that this insn
; can be placed. If the distance is zero, then this insn will never
; reference the pool.
; Note that for Thumb constant pools the PC value is rounded down to the
; nearest multiple of four. Therefore, THUMB2_POOL_RANGE (and POOL_RANGE for
; Thumb insns) should be set to <max_range> - 2.
; NEG_POOL_RANGE is nonzero for insns that can reference a constant pool entry
; before its address. It is set to <max_range> - (8 + <data_size>).
(define_attr "arm_pool_range" "" (const_int 0))
(define_attr "thumb2_pool_range" "" (const_int 0))
(define_attr "arm_neg_pool_range" "" (const_int 0))
(define_attr "thumb2_neg_pool_range" "" (const_int 0))
(define_attr "pool_range" ""
(cond [(eq_attr "is_thumb" "yes") (attr "thumb2_pool_range")]
(attr "arm_pool_range")))
(define_attr "neg_pool_range" ""
(cond [(eq_attr "is_thumb" "yes") (attr "thumb2_neg_pool_range")]
(attr "arm_neg_pool_range")))
; An assembler sequence may clobber the condition codes without us knowing.
; If such an insn references the pool, then we have no way of knowing how,
; so use the most conservative value for pool_range.
(define_asm_attributes
[(set_attr "conds" "clob")
(set_attr "length" "4")
(set_attr "pool_range" "250")])
; Load scheduling, set from the arm_ld_sched variable
; initialized by arm_option_override()
(define_attr "ldsched" "no,yes" (const (symbol_ref "arm_ld_sched")))
; 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
;
; UNCONDITIONAL means the instruction cannot be conditionally executed and
; that the instruction does not use or alter the condition codes.
;
; NOCOND means that the instruction does not use or alter the condition
; codes but can be converted into a conditionally exectuted instruction.
(define_attr "conds" "use,set,clob,unconditional,nocond"
(if_then_else
(ior (eq_attr "is_thumb1" "yes")
(eq_attr "type" "call"))
(const_string "clob")
(if_then_else
(ior (eq_attr "is_neon_type" "yes")
(eq_attr "is_mve_type" "yes"))
(const_string "unconditional")
(const_string "nocond"))))
; Predicable means that the insn can be conditionally executed based on
; an automatically added predicate (additional patterns are generated by
; gen...). We default to 'no' because no Thumb patterns match this rule
; and not all ARM patterns do.
(define_attr "predicable" "no,yes" (const_string "no"))
; 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 warrant modelling this (and it can adversely
; affect the schedule).
(define_attr "model_wbuf" "no,yes" (const (symbol_ref "arm_tune_wbuf")))
; WRITE_CONFLICT implies that a read following an unrelated write is likely
; to stall the processor. Used with model_wbuf above.
(define_attr "write_conflict" "no,yes"
(if_then_else (eq_attr "type"
"block,call,load_4")
(const_string "yes")
(const_string "no")))
; Classify the insns into those that take one cycle and those that take more
; than one on the main cpu execution unit.
(define_attr "core_cycles" "single,multi"
(if_then_else (eq_attr "type"
"adc_imm, adc_reg, adcs_imm, adcs_reg, adr, alu_ext, alu_imm, alu_sreg,\
alu_shift_imm_lsl_1to4, alu_shift_imm_other, alu_shift_reg, alu_dsp_reg,\
alus_ext, alus_imm, alus_sreg,\
alus_shift_imm, alus_shift_reg, bfm, csel, rev, logic_imm, logic_reg,\
logic_shift_imm, logic_shift_reg, logics_imm, logics_reg,\
logics_shift_imm, logics_shift_reg, extend, shift_imm, float, fcsel,\
wmmx_wor, wmmx_wxor, wmmx_wand, wmmx_wandn, wmmx_wmov, wmmx_tmcrr,\
wmmx_tmrrc, wmmx_wldr, wmmx_wstr, wmmx_tmcr, wmmx_tmrc, wmmx_wadd,\
wmmx_wsub, wmmx_wmul, wmmx_wmac, wmmx_wavg2, wmmx_tinsr, wmmx_textrm,\
wmmx_wshufh, wmmx_wcmpeq, wmmx_wcmpgt, wmmx_wmax, wmmx_wmin, wmmx_wpack,\
wmmx_wunpckih, wmmx_wunpckil, wmmx_wunpckeh, wmmx_wunpckel, wmmx_wror,\
wmmx_wsra, wmmx_wsrl, wmmx_wsll, wmmx_wmadd, wmmx_tmia, wmmx_tmiaph,\
wmmx_tmiaxy, wmmx_tbcst, wmmx_tmovmsk, wmmx_wacc, wmmx_waligni,\
wmmx_walignr, wmmx_tandc, wmmx_textrc, wmmx_torc, wmmx_torvsc, wmmx_wsad,\
wmmx_wabs, wmmx_wabsdiff, wmmx_waddsubhx, wmmx_wsubaddhx, wmmx_wavg4,\
wmmx_wmulw, wmmx_wqmulm, wmmx_wqmulwm, wmmx_waddbhus, wmmx_wqmiaxy,\
wmmx_wmiaxy, wmmx_wmiawxy, wmmx_wmerge")
(const_string "single")
(const_string "multi")))
;; FAR_JUMP is "yes" if a BL instruction is used to generate a branch to a
;; distant label. Only applicable to Thumb code.
(define_attr "far_jump" "yes,no" (const_string "no"))
;; The number of machine instructions this pattern expands to.
;; Used for Thumb-2 conditional execution.
(define_attr "ce_count" "" (const_int 1))
;;---------------------------------------------------------------------------
;; Unspecs
(include "unspecs.md")
;;---------------------------------------------------------------------------
;; Mode iterators
(include "iterators.md")
;;---------------------------------------------------------------------------
;; Predicates
(include "predicates.md")
(include "constraints.md")
;;---------------------------------------------------------------------------
;; Pipeline descriptions
(define_attr "tune_cortexr4" "yes,no"
(const (if_then_else
(eq_attr "tune" "cortexr4,cortexr4f,cortexr5")
(const_string "yes")
(const_string "no"))))
;; True if the generic scheduling description should be used.
(define_attr "generic_sched" "yes,no"
(const (if_then_else
(ior (eq_attr "tune" "fa526,fa626,fa606te,fa626te,fmp626,fa726te,\
arm926ejs,arm10e,arm1026ejs,arm1136js,\
arm1136jfs,cortexa5,cortexa7,cortexa8,\
cortexa9,cortexa12,cortexa15,cortexa17,\
cortexa53,cortexa57,cortexm4,cortexm7,\
exynosm1,marvell_pj4,xgene1")
(eq_attr "tune_cortexr4" "yes"))
(const_string "no")
(const_string "yes"))))
(define_attr "generic_vfp" "yes,no"
(const (if_then_else
(and (eq_attr "fpu" "vfp")
(eq_attr "tune" "!arm10e,cortexa5,cortexa7,\
cortexa8,cortexa9,cortexa53,cortexm4,\
cortexm7,marvell_pj4,xgene1")
(eq_attr "tune_cortexr4" "no"))
(const_string "yes")
(const_string "no"))))
(include "marvell-f-iwmmxt.md")
(include "arm-generic.md")
(include "arm926ejs.md")
(include "arm1020e.md")
(include "arm1026ejs.md")
(include "arm1136jfs.md")
(include "fa526.md")
(include "fa606te.md")
(include "fa626te.md")
(include "fmp626.md")
(include "fa726te.md")
(include "cortex-a5.md")
(include "cortex-a7.md")
(include "cortex-a8.md")
(include "cortex-a9.md")
(include "cortex-a15.md")
(include "cortex-a17.md")
(include "cortex-a53.md")
(include "cortex-a57.md")
(include "cortex-r4.md")
(include "cortex-r4f.md")
(include "cortex-m7.md")
(include "cortex-m4.md")
(include "cortex-m4-fpu.md")
(include "exynos-m1.md")
(include "vfp11.md")
(include "marvell-pj4.md")
(include "xgene1.md")
;; define_subst and associated attributes
(define_subst "add_setq"
[(set (match_operand:SI 0 "" "")
(match_operand:SI 1 "" ""))]
""
[(set (match_dup 0)
(match_dup 1))
(set (reg:CC APSRQ_REGNUM)
(unspec:CC [(reg:CC APSRQ_REGNUM)] UNSPEC_Q_SET))])
(define_subst_attr "add_clobber_q_name" "add_setq" "" "_setq")
(define_subst_attr "add_clobber_q_pred" "add_setq" "!ARM_Q_BIT_READ"
"ARM_Q_BIT_READ")
;;---------------------------------------------------------------------------
;; Insn patterns
;;
;; Addition insns.
;; 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.
(define_expand "adddi3"
[(parallel
[(set (match_operand:DI 0 "s_register_operand")
(plus:DI (match_operand:DI 1 "s_register_operand")
(match_operand:DI 2 "reg_or_int_operand")))
(clobber (reg:CC CC_REGNUM))])]
"TARGET_EITHER"
"
if (TARGET_THUMB1)
{
if (!REG_P (operands[2]))
operands[2] = force_reg (DImode, operands[2]);
}
else
{
rtx lo_result, hi_result, lo_dest, hi_dest;
rtx lo_op1, hi_op1, lo_op2, hi_op2;
arm_decompose_di_binop (operands[1], operands[2], &lo_op1, &hi_op1,
&lo_op2, &hi_op2);
lo_result = lo_dest = gen_lowpart (SImode, operands[0]);
hi_result = hi_dest = gen_highpart (SImode, operands[0]);
if (lo_op2 == const0_rtx)
{
lo_dest = lo_op1;
if (!arm_add_operand (hi_op2, SImode))
hi_op2 = force_reg (SImode, hi_op2);
/* Assume hi_op2 won't also be zero. */
emit_insn (gen_addsi3 (hi_dest, hi_op1, hi_op2));
}
else
{
if (!arm_add_operand (lo_op2, SImode))
lo_op2 = force_reg (SImode, lo_op2);
if (!arm_not_operand (hi_op2, SImode))
hi_op2 = force_reg (SImode, hi_op2);
emit_insn (gen_addsi3_compare_op1 (lo_dest, lo_op1, lo_op2));
rtx carry = gen_rtx_LTU (SImode, gen_rtx_REG (CC_Cmode, CC_REGNUM),
const0_rtx);
if (hi_op2 == const0_rtx)
emit_insn (gen_add0si3_carryin (hi_dest, hi_op1, carry));
else
emit_insn (gen_addsi3_carryin (hi_dest, hi_op1, hi_op2, carry));
}
if (lo_result != lo_dest)
emit_move_insn (lo_result, lo_dest);
if (hi_result != hi_dest)
emit_move_insn (gen_highpart (SImode, operands[0]), hi_dest);
DONE;
}
"
)
(define_expand "addvsi4"
[(match_operand:SI 0 "s_register_operand")
(match_operand:SI 1 "s_register_operand")
(match_operand:SI 2 "arm_add_operand")
(match_operand 3 "")]
"TARGET_32BIT"
{
if (CONST_INT_P (operands[2]))
emit_insn (gen_addsi3_compareV_imm (operands[0], operands[1], operands[2]));
else
emit_insn (gen_addsi3_compareV_reg (operands[0], operands[1], operands[2]));
arm_gen_unlikely_cbranch (NE, CC_Vmode, operands[3]);
DONE;
})
(define_expand "addvdi4"
[(match_operand:DI 0 "s_register_operand")
(match_operand:DI 1 "s_register_operand")
(match_operand:DI 2 "reg_or_int_operand")
(match_operand 3 "")]
"TARGET_32BIT"
{
rtx lo_result, hi_result;
rtx lo_op1, hi_op1, lo_op2, hi_op2;
arm_decompose_di_binop (operands[1], operands[2], &lo_op1, &hi_op1,
&lo_op2, &hi_op2);
lo_result = gen_lowpart (SImode, operands[0]);
hi_result = gen_highpart (SImode, operands[0]);
if (lo_op2 == const0_rtx)
{
emit_move_insn (lo_result, lo_op1);
if (!arm_add_operand (hi_op2, SImode))
hi_op2 = force_reg (SImode, hi_op2);
emit_insn (gen_addvsi4 (hi_result, hi_op1, hi_op2, operands[3]));
}
else
{
if (!arm_add_operand (lo_op2, SImode))
lo_op2 = force_reg (SImode, lo_op2);
if (!arm_not_operand (hi_op2, SImode))
hi_op2 = force_reg (SImode, hi_op2);
emit_insn (gen_addsi3_compare_op1 (lo_result, lo_op1, lo_op2));
if (hi_op2 == const0_rtx)
emit_insn (gen_addsi3_cin_vout_0 (hi_result, hi_op1));
else if (CONST_INT_P (hi_op2))
emit_insn (gen_addsi3_cin_vout_imm (hi_result, hi_op1, hi_op2));
else
emit_insn (gen_addsi3_cin_vout_reg (hi_result, hi_op1, hi_op2));
arm_gen_unlikely_cbranch (NE, CC_Vmode, operands[3]);
}
DONE;
})
(define_expand "addsi3_cin_vout_reg"
[(parallel
[(set (match_dup 3)
(compare:CC_V
(plus:DI
(plus:DI (match_dup 4)
(sign_extend:DI (match_operand:SI 1 "s_register_operand")))
(sign_extend:DI (match_operand:SI 2 "s_register_operand")))
(sign_extend:DI (plus:SI (plus:SI (match_dup 5) (match_dup 1))
(match_dup 2)))))
(set (match_operand:SI 0 "s_register_operand")
(plus:SI (plus:SI (match_dup 5) (match_dup 1))
(match_dup 2)))])]
"TARGET_32BIT"
{
operands[3] = gen_rtx_REG (CC_Vmode, CC_REGNUM);
rtx ccin = gen_rtx_REG (CC_Cmode, CC_REGNUM);
operands[4] = gen_rtx_LTU (DImode, ccin, const0_rtx);
operands[5] = gen_rtx_LTU (SImode, ccin, const0_rtx);
}
)
(define_insn "*addsi3_cin_vout_reg_insn"
[(set (reg:CC_V CC_REGNUM)
(compare:CC_V
(plus:DI
(plus:DI
(match_operand:DI 3 "arm_carry_operation" "")
(sign_extend:DI (match_operand:SI 1 "s_register_operand" "%0,r")))
(sign_extend:DI (match_operand:SI 2 "s_register_operand" "l,r")))
(sign_extend:DI
(plus:SI (plus:SI (match_operand:SI 4 "arm_carry_operation" "")
(match_dup 1))
(match_dup 2)))))
(set (match_operand:SI 0 "s_register_operand" "=l,r")
(plus:SI (plus:SI (match_dup 4) (match_dup 1))
(match_dup 2)))]
"TARGET_32BIT"
"@
adcs%?\\t%0, %0, %2
adcs%?\\t%0, %1, %2"
[(set_attr "type" "alus_sreg")
(set_attr "arch" "t2,*")
(set_attr "length" "2,4")]
)
(define_expand "addsi3_cin_vout_imm"
[(parallel
[(set (match_dup 3)
(compare:CC_V
(plus:DI
(plus:DI (match_dup 4)
(sign_extend:DI (match_operand:SI 1 "s_register_operand")))
(match_dup 2))
(sign_extend:DI (plus:SI (plus:SI (match_dup 5) (match_dup 1))
(match_dup 2)))))
(set (match_operand:SI 0 "s_register_operand")
(plus:SI (plus:SI (match_dup 5) (match_dup 1))
(match_operand 2 "arm_adcimm_operand")))])]
"TARGET_32BIT"
{
operands[3] = gen_rtx_REG (CC_Vmode, CC_REGNUM);
rtx ccin = gen_rtx_REG (CC_Cmode, CC_REGNUM);
operands[4] = gen_rtx_LTU (DImode, ccin, const0_rtx);
operands[5] = gen_rtx_LTU (SImode, ccin, const0_rtx);
}
)
(define_insn "*addsi3_cin_vout_imm_insn"
[(set (reg:CC_V CC_REGNUM)
(compare:CC_V
(plus:DI
(plus:DI
(match_operand:DI 3 "arm_carry_operation" "")
(sign_extend:DI (match_operand:SI 1 "s_register_operand" "r,r")))
(match_operand 2 "arm_adcimm_operand" "I,K"))
(sign_extend:DI
(plus:SI (plus:SI (match_operand:SI 4 "arm_carry_operation" "")
(match_dup 1))
(match_dup 2)))))
(set (match_operand:SI 0 "s_register_operand" "=r,r")
(plus:SI (plus:SI (match_dup 4) (match_dup 1))
(match_dup 2)))]
"TARGET_32BIT"
"@
adcs%?\\t%0, %1, %2
sbcs%?\\t%0, %1, #%B2"
[(set_attr "type" "alus_imm")]
)
(define_expand "addsi3_cin_vout_0"
[(parallel
[(set (match_dup 2)
(compare:CC_V
(plus:DI (match_dup 3)
(sign_extend:DI (match_operand:SI 1 "s_register_operand")))
(sign_extend:DI (plus:SI (match_dup 4) (match_dup 1)))))
(set (match_operand:SI 0 "s_register_operand")
(plus:SI (match_dup 4) (match_dup 1)))])]
"TARGET_32BIT"
{
operands[2] = gen_rtx_REG (CC_Vmode, CC_REGNUM);
rtx ccin = gen_rtx_REG (CC_Cmode, CC_REGNUM);
operands[3] = gen_rtx_LTU (DImode, ccin, const0_rtx);
operands[4] = gen_rtx_LTU (SImode, ccin, const0_rtx);
}
)
(define_insn "*addsi3_cin_vout_0_insn"
[(set (reg:CC_V CC_REGNUM)
(compare:CC_V
(plus:DI
(match_operand:DI 2 "arm_carry_operation" "")
(sign_extend:DI (match_operand:SI 1 "s_register_operand" "r")))
(sign_extend:DI (plus:SI
(match_operand:SI 3 "arm_carry_operation" "")
(match_dup 1)))))
(set (match_operand:SI 0 "s_register_operand" "=r")
(plus:SI (match_dup 3) (match_dup 1)))]
"TARGET_32BIT"
"adcs%?\\t%0, %1, #0"
[(set_attr "type" "alus_imm")]
)
(define_expand "uaddvsi4"
[(match_operand:SI 0 "s_register_operand")
(match_operand:SI 1 "s_register_operand")
(match_operand:SI 2 "arm_add_operand")
(match_operand 3 "")]
"TARGET_32BIT"
{
emit_insn (gen_addsi3_compare_op1 (operands[0], operands[1], operands[2]));
arm_gen_unlikely_cbranch (LTU, CC_Cmode, operands[3]);
DONE;
})
(define_expand "uaddvdi4"
[(match_operand:DI 0 "s_register_operand")
(match_operand:DI 1 "s_register_operand")
(match_operand:DI 2 "reg_or_int_operand")
(match_operand 3 "")]
"TARGET_32BIT"
{
rtx lo_result, hi_result;
rtx lo_op1, hi_op1, lo_op2, hi_op2;
arm_decompose_di_binop (operands[1], operands[2], &lo_op1, &hi_op1,
&lo_op2, &hi_op2);
lo_result = gen_lowpart (SImode, operands[0]);
hi_result = gen_highpart (SImode, operands[0]);
if (lo_op2 == const0_rtx)
{
emit_move_insn (lo_result, lo_op1);
if (!arm_add_operand (hi_op2, SImode))
hi_op2 = force_reg (SImode, hi_op2);
emit_insn (gen_uaddvsi4 (hi_result, hi_op1, hi_op2, operands[3]));
}
else
{
if (!arm_add_operand (lo_op2, SImode))
lo_op2 = force_reg (SImode, lo_op2);
if (!arm_not_operand (hi_op2, SImode))
hi_op2 = force_reg (SImode, hi_op2);
emit_insn (gen_addsi3_compare_op1 (lo_result, lo_op1, lo_op2));
if (hi_op2 == const0_rtx)
emit_insn (gen_addsi3_cin_cout_0 (hi_result, hi_op1));
else if (CONST_INT_P (hi_op2))
emit_insn (gen_addsi3_cin_cout_imm (hi_result, hi_op1, hi_op2));
else
emit_insn (gen_addsi3_cin_cout_reg (hi_result, hi_op1, hi_op2));
arm_gen_unlikely_cbranch (GEU, CC_ADCmode, operands[3]);
}
DONE;
})
(define_expand "addsi3_cin_cout_reg"
[(parallel
[(set (match_dup 3)
(compare:CC_ADC
(plus:DI
(plus:DI (match_dup 4)
(zero_extend:DI (match_operand:SI 1 "s_register_operand")))
(zero_extend:DI (match_operand:SI 2 "s_register_operand")))
(const_int 4294967296)))
(set (match_operand:SI 0 "s_register_operand")
(plus:SI (plus:SI (match_dup 5) (match_dup 1))
(match_dup 2)))])]
"TARGET_32BIT"
{
operands[3] = gen_rtx_REG (CC_ADCmode, CC_REGNUM);
rtx ccin = gen_rtx_REG (CC_Cmode, CC_REGNUM);
operands[4] = gen_rtx_LTU (DImode, ccin, const0_rtx);
operands[5] = gen_rtx_LTU (SImode, ccin, const0_rtx);
}
)
(define_insn "*addsi3_cin_cout_reg_insn"
[(set (reg:CC_ADC CC_REGNUM)
(compare:CC_ADC
(plus:DI
(plus:DI
(match_operand:DI 3 "arm_carry_operation" "")
(zero_extend:DI (match_operand:SI 1 "s_register_operand" "%0,r")))
(zero_extend:DI (match_operand:SI 2 "s_register_operand" "l,r")))
(const_int 4294967296)))
(set (match_operand:SI 0 "s_register_operand" "=l,r")
(plus:SI (plus:SI (match_operand:SI 4 "arm_carry_operation" "")
(match_dup 1))
(match_dup 2)))]
"TARGET_32BIT"
"@
adcs%?\\t%0, %0, %2
adcs%?\\t%0, %1, %2"
[(set_attr "type" "alus_sreg")
(set_attr "arch" "t2,*")
(set_attr "length" "2,4")]
)
(define_expand "addsi3_cin_cout_imm"
[(parallel
[(set (match_dup 3)
(compare:CC_ADC
(plus:DI
(plus:DI (match_dup 4)
(zero_extend:DI (match_operand:SI 1 "s_register_operand")))
(match_dup 6))
(const_int 4294967296)))
(set (match_operand:SI 0 "s_register_operand")
(plus:SI (plus:SI (match_dup 5) (match_dup 1))
(match_operand:SI 2 "arm_adcimm_operand")))])]
"TARGET_32BIT"
{
operands[3] = gen_rtx_REG (CC_ADCmode, CC_REGNUM);
rtx ccin = gen_rtx_REG (CC_Cmode, CC_REGNUM);
operands[4] = gen_rtx_LTU (DImode, ccin, const0_rtx);
operands[5] = gen_rtx_LTU (SImode, ccin, const0_rtx);
operands[6] = GEN_INT (UINTVAL (operands[2]) & 0xffffffff);
}
)
(define_insn "*addsi3_cin_cout_imm_insn"
[(set (reg:CC_ADC CC_REGNUM)
(compare:CC_ADC
(plus:DI
(plus:DI
(match_operand:DI 3 "arm_carry_operation" "")
(zero_extend:DI (match_operand:SI 1 "s_register_operand" "r,r")))
(match_operand:DI 5 "const_int_operand" "n,n"))
(const_int 4294967296)))
(set (match_operand:SI 0 "s_register_operand" "=r,r")
(plus:SI (plus:SI (match_operand:SI 4 "arm_carry_operation" "")
(match_dup 1))
(match_operand:SI 2 "arm_adcimm_operand" "I,K")))]
"TARGET_32BIT
&& (UINTVAL (operands[2]) & 0xffffffff) == UINTVAL (operands[5])"
"@
adcs%?\\t%0, %1, %2
sbcs%?\\t%0, %1, #%B2"
[(set_attr "type" "alus_imm")]
)
(define_expand "addsi3_cin_cout_0"
[(parallel
[(set (match_dup 2)
(compare:CC_ADC
(plus:DI (match_dup 3)
(zero_extend:DI (match_operand:SI 1 "s_register_operand")))
(const_int 4294967296)))
(set (match_operand:SI 0 "s_register_operand")
(plus:SI (match_dup 4) (match_dup 1)))])]
"TARGET_32BIT"
{
operands[2] = gen_rtx_REG (CC_ADCmode, CC_REGNUM);
rtx ccin = gen_rtx_REG (CC_Cmode, CC_REGNUM);
operands[3] = gen_rtx_LTU (DImode, ccin, const0_rtx);
operands[4] = gen_rtx_LTU (SImode, ccin, const0_rtx);
}
)
(define_insn "*addsi3_cin_cout_0_insn"
[(set (reg:CC_ADC CC_REGNUM)
(compare:CC_ADC
(plus:DI
(match_operand:DI 2 "arm_carry_operation" "")
(zero_extend:DI (match_operand:SI 1 "s_register_operand" "r")))
(const_int 4294967296)))
(set (match_operand:SI 0 "s_register_operand" "=r")
(plus:SI (match_operand:SI 3 "arm_carry_operation" "") (match_dup 1)))]
"TARGET_32BIT"
"adcs%?\\t%0, %1, #0"
[(set_attr "type" "alus_imm")]
)
(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")))]
"TARGET_EITHER"
"
if (TARGET_32BIT && CONST_INT_P (operands[2]))
{
arm_split_constant (PLUS, SImode, NULL_RTX,
INTVAL (operands[2]), operands[0], operands[1],
optimize && can_create_pseudo_p ());
DONE;
}
"
)
; If there is a scratch available, this will be faster than synthesizing the
; addition.
(define_peephole2
[(match_scratch:SI 3 "r")
(set (match_operand:SI 0 "arm_general_register_operand" "")
(plus:SI (match_operand:SI 1 "arm_general_register_operand" "")
(match_operand:SI 2 "const_int_operand" "")))]
"TARGET_32BIT &&
!(const_ok_for_arm (INTVAL (operands[2]))
|| const_ok_for_arm (-INTVAL (operands[2])))
&& const_ok_for_arm (~INTVAL (operands[2]))"
[(set (match_dup 3) (match_dup 2))
(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 3)))]
""
)
;; The r/r/k alternative is required when reloading the address
;; (plus (reg rN) (reg sp)) into (reg rN). In this case reload will
;; put the duplicated register first, and not try the commutative version.
(define_insn_and_split "*arm_addsi3"
[(set (match_operand:SI 0 "s_register_operand" "=rk,l,l ,l ,r ,k ,r,k ,r ,k ,r ,k,k,r ,k ,r")
(plus:SI (match_operand:SI 1 "s_register_operand" "%0 ,l,0 ,l ,rk,k ,r,r ,rk,k ,rk,k,r,rk,k ,rk")
(match_operand:SI 2 "reg_or_int_operand" "rk ,l,Py,Pd,rI,rI,k,rI,Pj,Pj,L ,L,L,PJ,PJ,?n")))]
"TARGET_32BIT"
"@
add%?\\t%0, %0, %2
add%?\\t%0, %1, %2
add%?\\t%0, %1, %2
add%?\\t%0, %1, %2
add%?\\t%0, %1, %2
add%?\\t%0, %1, %2
add%?\\t%0, %2, %1
add%?\\t%0, %1, %2
addw%?\\t%0, %1, %2
addw%?\\t%0, %1, %2
sub%?\\t%0, %1, #%n2
sub%?\\t%0, %1, #%n2
sub%?\\t%0, %1, #%n2
subw%?\\t%0, %1, #%n2
subw%?\\t%0, %1, #%n2
#"
"TARGET_32BIT
&& CONST_INT_P (operands[2])
&& !const_ok_for_op (INTVAL (operands[2]), PLUS)
&& (reload_completed || !arm_eliminable_register (operands[1]))"
[(clobber (const_int 0))]
"
arm_split_constant (PLUS, SImode, curr_insn,
INTVAL (operands[2]), operands[0],
operands[1], 0);
DONE;
"
[(set_attr "length" "2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,16")
(set_attr "predicable" "yes")
(set_attr "predicable_short_it" "yes,yes,yes,yes,no,no,no,no,no,no,no,no,no,no,no,no")
(set_attr "arch" "t2,t2,t2,t2,*,*,*,a,t2,t2,*,*,a,t2,t2,*")
(set (attr "type") (if_then_else (match_operand 2 "const_int_operand" "")
(const_string "alu_imm")
(const_string "alu_sreg")))
]
)
(define_insn "addsi3_compareV_reg"
[(set (reg:CC_V CC_REGNUM)
(compare:CC_V
(plus:DI
(sign_extend:DI (match_operand:SI 1 "register_operand" "%l,0,r"))
(sign_extend:DI (match_operand:SI 2 "register_operand" "l,r,r")))
(sign_extend:DI (plus:SI (match_dup 1) (match_dup 2)))))
(set (match_operand:SI 0 "register_operand" "=l,r,r")
(plus:SI (match_dup 1) (match_dup 2)))]
"TARGET_32BIT"
"adds%?\\t%0, %1, %2"
[(set_attr "conds" "set")
(set_attr "arch" "t2,t2,*")
(set_attr "length" "2,2,4")
(set_attr "type" "alus_sreg")]
)
(define_insn "*addsi3_compareV_reg_nosum"
[(set (reg:CC_V CC_REGNUM)
(compare:CC_V
(plus:DI
(sign_extend:DI (match_operand:SI 0 "register_operand" "%l,r"))
(sign_extend:DI (match_operand:SI 1 "register_operand" "l,r")))
(sign_extend:DI (plus:SI (match_dup 0) (match_dup 1)))))]
"TARGET_32BIT"
"cmn%?\\t%0, %1"
[(set_attr "conds" "set")
(set_attr "arch" "t2,*")
(set_attr "length" "2,4")
(set_attr "type" "alus_sreg")]
)
(define_insn "subvsi3_intmin"
[(set (reg:CC_V CC_REGNUM)
(compare:CC_V
(plus:DI
(sign_extend:DI
(match_operand:SI 1 "register_operand" "r"))
(const_int 2147483648))
(sign_extend:DI (plus:SI (match_dup 1) (const_int -2147483648)))))
(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (match_dup 1) (const_int -2147483648)))]
"TARGET_32BIT"
"subs%?\\t%0, %1, #-2147483648"
[(set_attr "conds" "set")
(set_attr "type" "alus_imm")]
)
(define_insn "addsi3_compareV_imm"
[(set (reg:CC_V CC_REGNUM)
(compare:CC_V
(plus:DI
(sign_extend:DI
(match_operand:SI 1 "register_operand" "l,0,l,0,r,r"))
(match_operand 2 "arm_addimm_operand" "Pd,Py,Px,Pw,I,L"))
(sign_extend:DI (plus:SI (match_dup 1) (match_dup 2)))))
(set (match_operand:SI 0 "register_operand" "=l,l,l,l,r,r")
(plus:SI (match_dup 1) (match_dup 2)))]
"TARGET_32BIT
&& INTVAL (operands[2]) == ARM_SIGN_EXTEND (INTVAL (operands[2]))"
"@
adds%?\\t%0, %1, %2
adds%?\\t%0, %0, %2
subs%?\\t%0, %1, #%n2
subs%?\\t%0, %0, #%n2
adds%?\\t%0, %1, %2
subs%?\\t%0, %1, #%n2"
[(set_attr "conds" "set")
(set_attr "arch" "t2,t2,t2,t2,*,*")
(set_attr "length" "2,2,2,2,4,4")
(set_attr "type" "alus_imm")]
)
(define_insn "addsi3_compareV_imm_nosum"
[(set (reg:CC_V CC_REGNUM)
(compare:CC_V
(plus:DI
(sign_extend:DI
(match_operand:SI 0 "register_operand" "l,r,r"))
(match_operand 1 "arm_addimm_operand" "Pw,I,L"))
(sign_extend:DI (plus:SI (match_dup 0) (match_dup 1)))))]
"TARGET_32BIT
&& INTVAL (operands[1]) == ARM_SIGN_EXTEND (INTVAL (operands[1]))"
"@
cmp%?\\t%0, #%n1
cmn%?\\t%0, %1
cmp%?\\t%0, #%n1"
[(set_attr "conds" "set")
(set_attr "arch" "t2,*,*")
(set_attr "length" "2,4,4")
(set_attr "type" "alus_imm")]
)
;; We can handle more constants efficently if we can clobber either a scratch
;; or the other source operand. We deliberately leave this late as in
;; high register pressure situations it's not worth forcing any reloads.
(define_peephole2
[(match_scratch:SI 2 "l")
(set (reg:CC_V CC_REGNUM)
(compare:CC_V
(plus:DI
(sign_extend:DI
(match_operand:SI 0 "low_register_operand"))
(match_operand 1 "const_int_operand"))
(sign_extend:DI (plus:SI (match_dup 0) (match_dup 1)))))]
"TARGET_THUMB2
&& satisfies_constraint_Pd (operands[1])"
[(parallel[
(set (reg:CC_V CC_REGNUM)
(compare:CC_V
(plus:DI (sign_extend:DI (match_dup 0))
(sign_extend:DI (match_dup 1)))
(sign_extend:DI (plus:SI (match_dup 0) (match_dup 1)))))
(set (match_dup 2) (plus:SI (match_dup 0) (match_dup 1)))])]
)
(define_peephole2
[(set (reg:CC_V CC_REGNUM)
(compare:CC_V
|