+++ /dev/null
-;; thumb.md Machine description for ARM/Thumb processors
-;; Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
-;; The basis of this contribution was generated by
-;; Richard Earnshaw, Advanced RISC Machines Ltd
-
-;; 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.
-
-;; LENGTH of an instruction is 2 bytes
-(define_attr "length" "" (const_int 2))
-
-;; CONDS is set to UNCHANGED when an insn does not affect the condition codes
-;; Most insns change the condition codes
-(define_attr "conds" "changed,unchanged" (const_string "changed"))
-
-;; FAR_JUMP is "yes" if a BL instruction is used to generate a branch to a
-;; distant label.
-(define_attr "far_jump" "yes,no" (const_string "no"))
-
-;; Start with move insns
-
-(define_expand "movsi"
- [(set (match_operand:SI 0 "general_operand" "")
- (match_operand:SI 1 "general_operand" ""))]
- ""
- "
- if (! (reload_in_progress || reload_completed))
- {
- if (GET_CODE (operands[0]) != REG)
- operands[1] = force_reg (SImode, operands[1]);
- }
- 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 "nonimmediate_operand" "=l,l,l,l,l,>,l,m,*r,*h")
- (match_operand:SI 1 "general_operand" "l,I,J,K,>,l,mi,l,*h,*r"))]
- "register_operand (operands[0], SImode)
- || register_operand (operands[1], SImode)"
- "@
- add\\t%0, %1, #0
- mov\\t%0, %1
- #
- #
- ldmia\\t%1, {%0}
- stmia\\t%0, {%1}
- ldr\\t%0, %1
- str\\t%1, %0
- mov\\t%0, %1
- mov\\t%0, %1"
-[(set_attr "length" "2,2,4,4,2,2,2,2,2,2")])
-
-(define_split
- [(set (match_operand:SI 0 "register_operand" "")
- (match_operand:SI 1 "const_int_operand" ""))]
- "thumb_shiftable_const (INTVAL (operands[1]))"
- [(set (match_dup 0) (match_dup 1))
- (set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))]
- "
-{
- unsigned HOST_WIDE_INT val = INTVAL (operands[1]);
- unsigned HOST_WIDE_INT mask = 0xff;
- int i;
- for (i = 0; i < 25; i++)
- if ((val & (mask << i)) == val)
- break;
-
- if (i == 0)
- FAIL;
-
- operands[1] = GEN_INT (val >> i);
- operands[2] = GEN_INT (i);
-}")
-
-(define_split
- [(set (match_operand:SI 0 "register_operand" "")
- (match_operand:SI 1 "const_int_operand" ""))]
- "INTVAL (operands[1]) < 0 && INTVAL (operands[1]) > -256"
- [(set (match_dup 0) (match_dup 1))
- (set (match_dup 0) (neg:SI (match_dup 0)))]
- "
- operands[1] = GEN_INT (- INTVAL (operands[1]));
-")
-
-;;(define_expand "reload_outsi"
-;; [(set (match_operand:SI 2 "register_operand" "=&l")
-;; (match_operand:SI 1 "register_operand" "h"))
-;; (set (match_operand:SI 0 "reload_memory_operand" "=o")
-;; (match_dup 2))]
-;; ""
-;; "
-;;/* thumb_reload_out_si (operands);
-;; DONE; */
-;;")
-
-(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]) != REG)
- operands[1] = force_reg (HImode, operands[1]);
-
- /* ??? We shouldn't really get invalid addresses here, but this can
- happen if we are passed a SP (never OK for HImode/QImode) or virtual
- register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode)
- relative address. */
- /* ??? This should perhaps be fixed elsewhere, for instance, in
- fixup_stack_1, by checking for other kinds of invalid addresses,
- e.g. a bare reference to a virtual register. This may confuse the
- alpha though, which must handle this case differently. */
- if (GET_CODE (operands[0]) == MEM
- && ! memory_address_p (GET_MODE (operands[0]),
- XEXP (operands[0], 0)))
- {
- rtx temp = copy_to_reg (XEXP (operands[0], 0));
- operands[0] = change_address (operands[0], VOIDmode, temp);
- }
- if (GET_CODE (operands[1]) == MEM
- && ! memory_address_p (GET_MODE (operands[1]),
- XEXP (operands[1], 0)))
- {
- rtx temp = copy_to_reg (XEXP (operands[1], 0));
- operands[1] = change_address (operands[1], VOIDmode, temp);
- }
- }
- /* Handle loading a large integer during reload */
- else if (GET_CODE (operands[1]) == CONST_INT
- && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I'))
- {
- /* 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 "*movhi_insn"
- [(set (match_operand:HI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l")
- (match_operand:HI 1 "general_operand" "l,m,l,*h,*r,I"))]
- "register_operand (operands[0], HImode)
- || register_operand (operands[1], HImode)"
- "@
- add\\t%0, %1, #0
- ldrh\\t%0, %1
- strh\\t%1, %0
- mov\\t%0, %1
- mov\\t%0, %1
- mov\\t%0, %1")
-
-(define_expand "movqi"
- [(set (match_operand:QI 0 "general_operand" "")
- (match_operand:QI 1 "general_operand" ""))]
- ""
- "
-{
- if (! (reload_in_progress || reload_completed))
- {
- if (GET_CODE (operands[0]) != REG)
- operands[1] = force_reg (QImode, operands[1]);
-
- /* ??? We shouldn't really get invalid addresses here, but this can
- happen if we are passed a SP (never OK for HImode/QImode) or virtual
- register (rejected by GO_IF_LEGITIMATE_ADDRESS for HImode/QImode)
- relative address. */
- /* ??? This should perhaps be fixed elsewhere, for instance, in
- fixup_stack_1, by checking for other kinds of invalid addresses,
- e.g. a bare reference to a virtual register. This may confuse the
- alpha though, which must handle this case differently. */
- if (GET_CODE (operands[0]) == MEM
- && ! memory_address_p (GET_MODE (operands[0]),
- XEXP (operands[0], 0)))
- {
- rtx temp = copy_to_reg (XEXP (operands[0], 0));
- operands[0] = change_address (operands[0], VOIDmode, temp);
- }
- if (GET_CODE (operands[1]) == MEM
- && ! memory_address_p (GET_MODE (operands[1]),
- XEXP (operands[1], 0)))
- {
- rtx temp = copy_to_reg (XEXP (operands[1], 0));
- operands[1] = change_address (operands[1], VOIDmode, temp);
- }
- }
- /* Handle loading a large integer during reload */
- else if (GET_CODE (operands[1]) == CONST_INT
- && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I'))
- {
- /* 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 "*movqi_insn"
- [(set (match_operand:QI 0 "nonimmediate_operand" "=l,l,m,*r,*h,l")
- (match_operand:QI 1 "general_operand" "l,m,l,*h,*r,I"))]
- "register_operand (operands[0], QImode)
- || register_operand (operands[1], QImode)"
- "@
- add\\t%0, %1, #0
- ldrb\\t%0, %1
- strb\\t%1, %0
- mov\\t%0, %1
- mov\\t%0, %1
- mov\\t%0, %1")
-
-(define_expand "movdi"
- [(set (match_operand:DI 0 "general_operand" "")
- (match_operand:DI 1 "general_operand" ""))]
- ""
- "
- if (! (reload_in_progress || reload_completed))
- {
- if (GET_CODE (operands[0]) != REG)
- operands[1] = force_reg (DImode, operands[1]);
- }
-")
-
-;;; ??? This should have alternatives for constants.
-;;; ??? This was originally identical to the movdf_insn pattern.
-;;; ??? The 'i' constraint looks funny, but it should always be replaced by
-;;; thumb_reorg with a memory reference.
-(define_insn "*movdi_insn"
- [(set (match_operand:DI 0 "general_operand" "=l,l,l,l,>,l,m,*r")
- (match_operand:DI 1 "general_operand" "l,I,J,>,l,mi,l,*r"))]
- "register_operand (operands[0], DImode)
- || register_operand (operands[1], DImode)"
- "*
-{
- switch (which_alternative)
- {
- default:
- abort ();
- case 0:
- if (REGNO (operands[1]) == REGNO (operands[0]) + 1)
- return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\";
- return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\";
- case 1:
- return \"mov\\t%Q0, %1\;mov\\t%R0, #0\";
- case 2:
- operands[1] = GEN_INT (- INTVAL (operands[1]));
- return \"mov\\t%Q0, %1\;neg\\t%Q0, %Q0\;asr\\t%R0, %Q0, #31\";
- case 3:
- return \"ldmia\\t%1, {%0, %H0}\";
- case 4:
- return \"stmia\\t%0, {%1, %H1}\";
- case 5:
- return thumb_load_double_from_address (operands);
- case 6:
- operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4));
- output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands);
- return \"\";
- case 7:
- if (REGNO (operands[1]) == REGNO (operands[0]) + 1)
- return \"mov\\t%0, %1\;mov\\t%H0, %H1\";
- return \"mov\\t%H0, %H1\;mov\\t%0, %1\";
- }
-}"[(set_attr "length" "4,4,6,2,2,6,4,4")])
-
-(define_expand "movdf"
- [(set (match_operand:DF 0 "general_operand" "")
- (match_operand:DF 1 "general_operand" ""))]
- ""
- "
- if (! (reload_in_progress || reload_completed))
- {
- if (GET_CODE (operands[0]) != REG)
- operands[1] = force_reg (DFmode, operands[1]);
- }
-")
-
-;;; ??? This should have alternatives for constants.
-;;; ??? This was originally identical to the movdi_insn pattern.
-;;; ??? The 'F' constraint looks funny, but it should always be replaced by
-;;; thumb_reorg with a memory reference.
-(define_insn "*movdf_insn"
- [(set (match_operand:DF 0 "general_operand" "=l,l,>,l,m,*r")
- (match_operand:DF 1 "general_operand" "l,>,l,mF,l,*r"))]
- "register_operand (operands[0], DFmode)
- || register_operand (operands[1], DFmode)"
- "*
- switch (which_alternative)
- {
- default:
- abort ();
- case 0:
- if (REGNO (operands[1]) == REGNO (operands[0]) + 1)
- return \"add\\t%0, %1, #0\;add\\t%H0, %H1, #0\";
- return \"add\\t%H0, %H1, #0\;add\\t%0, %1, #0\";
- case 1:
- return \"ldmia\\t%1, {%0, %H0}\";
- case 2:
- return \"stmia\\t%0, {%1, %H1}\";
- case 3:
- return thumb_load_double_from_address (operands);
- case 4:
- operands[2] = gen_rtx (MEM, SImode, plus_constant (XEXP (operands[0], 0), 4));
- output_asm_insn (\"str\\t%1, %0\;str\\t%H1, %2\", operands);
- return \"\";
- case 5:
- if (REGNO (operands[1]) == REGNO (operands[0]) + 1)
- return \"mov\\t%0, %1\;mov\\t%H0, %H1\";
- return \"mov\\t%H0, %H1\;mov\\t%0, %1\";
- }
-"[(set_attr "length" "4,2,2,6,4,4")])
-
-(define_expand "movsf"
- [(set (match_operand:SF 0 "general_operand" "")
- (match_operand:SF 1 "general_operand" ""))]
- ""
- "
- if (! (reload_in_progress || reload_completed))
- {
- if (GET_CODE (operands[0]) != REG)
- operands[1] = force_reg (SFmode, operands[1]);
- }
-")
-
-;;; ??? This should have alternatives for constants.
-(define_insn "*movsf_insn"
- [(set (match_operand:SF 0 "nonimmediate_operand" "=l,l,>,l,m,*r,*h")
- (match_operand:SF 1 "general_operand" "l,>,l,mF,l,*h,*r"))]
- "register_operand (operands[0], SFmode)
- || register_operand (operands[1], SFmode)"
- "@
- add\\t%0, %1, #0
- ldmia\\t%1, {%0}
- stmia\\t%0, {%1}
- ldr\\t%0, %1
- str\\t%1, %0
- mov\\t%0, %1
- mov\\t%0, %1")
-
-;; Widening move insns
-
-(define_expand "zero_extendhisi2"
- [(set (match_operand:SI 0 "register_operand" "")
- (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))]
- ""
- "
- if (GET_CODE (operands[1]) != MEM)
- {
- rtx temp = gen_reg_rtx (SImode);
-
- operands[1] = force_reg (HImode, operands[1]);
- operands[1] = gen_lowpart (SImode, operands[1]);
- emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16)));
- emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (16)));
- DONE;
- }
-")
-
-(define_insn "*zero_extendhisi2_insn"
- [(set (match_operand:SI 0 "register_operand" "=l")
- (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
- ""
- "ldrh\\t%0, %1")
-
-(define_expand "zero_extendqisi2"
- [(set (match_operand:SI 0 "register_operand" "")
- (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
- ""
- "
- if (GET_CODE (operands[1]) != MEM)
- {
- rtx temp = gen_reg_rtx (SImode);
-
- operands[1] = force_reg (QImode, operands[1]);
- operands[1] = gen_lowpart (SImode, operands[1]);
- emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24)));
- emit_insn (gen_lshrsi3 (operands[0], temp, GEN_INT (24)));
- DONE;
- }
-")
-
-(define_insn "*zero_extendqisi2_insn"
- [(set (match_operand:SI 0 "register_operand" "=l")
- (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
- ""
- "ldrb\\t%0, %1")
-
-(define_expand "extendhisi2"
- [(parallel [(set (match_operand:SI 0 "register_operand" "")
- (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))
- (clobber (match_scratch:SI 2 ""))])]
- ""
- "
- if (GET_CODE (operands[1]) != MEM)
- {
- rtx temp = gen_reg_rtx (SImode);
-
- operands[1] = force_reg (HImode, operands[1]);
- operands[1] = gen_lowpart (SImode, operands[1]);
- emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (16)));
- emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (16)));
- DONE;
- }
-")
-
-(define_insn "*extendhisi2_insn"
- [(set (match_operand:SI 0 "register_operand" "=l")
- (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))
- (clobber (match_scratch:SI 2 "=&l"))]
- ""
- "*
-{
- rtx ops[4];
- /* This code used to try to use 'V', and fix the address only if it was
- offsettable, but this fails for e.g. REG+48 because 48 is outside the
- range of QImode offsets, and offsettable_address_p does a QImode
- address check. */
-
- if (GET_CODE (XEXP (operands[1], 0)) == PLUS)
- {
- ops[1] = XEXP (XEXP (operands[1], 0), 0);
- ops[2] = XEXP (XEXP (operands[1], 0), 1);
- }
- else
- {
- ops[1] = XEXP (operands[1], 0);
- ops[2] = const0_rtx;
- }
- if (GET_CODE (ops[2]) == REG)
- return \"ldrsh\\t%0, %1\";
-
- ops[0] = operands[0];
- ops[3] = operands[2];
- output_asm_insn (\"mov\\t%3, %2\;ldrsh\\t%0, [%1, %3]\", ops);
- return \"\";
-}"
-[(set_attr "length" "4")])
-
-(define_expand "extendqisi2"
- [(set (match_operand:SI 0 "register_operand" "")
- (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
- ""
- "
- if (GET_CODE (operands[1]) != MEM)
- {
- rtx temp = gen_reg_rtx (SImode);
-
- operands[1] = force_reg (QImode, operands[1]);
- operands[1] = gen_lowpart (SImode, operands[1]);
- emit_insn (gen_ashlsi3 (temp, operands[1], GEN_INT (24)));
- emit_insn (gen_ashrsi3 (operands[0], temp, GEN_INT (24)));
- DONE;
- }
-")
-
-(define_insn "*extendqisi2_insn"
- [(set (match_operand:SI 0 "register_operand" "=l,l")
- (sign_extend:SI (match_operand:QI 1 "memory_operand" "V,m")))]
- ""
- "*
-{
- rtx ops[3];
-
- if (which_alternative == 0)
- return \"ldrsb\\t%0, %1\";
- ops[0] = operands[0];
- if (GET_CODE (XEXP (operands[1], 0)) == PLUS)
- {
- ops[1] = XEXP (XEXP (operands[1], 0), 0);
- ops[2] = XEXP (XEXP (operands[1], 0), 1);
-
- if (GET_CODE (ops[1]) == REG && GET_CODE (ops[2]) == REG)
- output_asm_insn (\"ldrsb\\t%0, [%1, %2]\", ops);
- else if (GET_CODE (ops[1]) == REG)
- {
- if (REGNO (ops[1]) == REGNO (operands[0]))
- output_asm_insn (\"ldrb\\t%0, [%1, %2]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops);
- else
- output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops);
- }
- else
- {
- if (REGNO (ops[2]) == REGNO (operands[0]))
- output_asm_insn (\"ldrb\\t%0, [%2, %1]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops);
- else
- output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops);
- }
- }
- else if (REGNO (operands[0]) == REGNO (XEXP (operands[1], 0)))
- {
- output_asm_insn (\"ldrb\\t%0, [%0, #0]\;lsl\\t%0, %0, #24\;asr\\t%0, %0, #24\", ops);
- }
- else
- {
- ops[1] = XEXP (operands[1], 0);
- ops[2] = const0_rtx;
- output_asm_insn (\"mov\\t%0, %2\;ldrsb\\t%0, [%1, %0]\", ops);
- }
- return \"\";
-}"
-[(set_attr "length" "2,6")])
-
-;; We don't really have extzv, but defining this using shifts helps
-;; to reduce register pressure later on.
-
-(define_expand "extzv"
- [(set (match_dup 4)
- (ashift:SI (match_operand:SI 1 "register_operand" "")
- (match_operand:SI 2 "const_int_operand" "")))
- (set (match_operand:SI 0 "register_operand" "")
- (lshiftrt:SI (match_dup 4)
- (match_operand:SI 3 "const_int_operand" "")))]
- ""
- "
-{
- HOST_WIDE_INT lshift = 32 - INTVAL (operands[2]) - INTVAL (operands[3]);
- HOST_WIDE_INT rshift = 32 - INTVAL (operands[2]);
- operands[3] = GEN_INT (rshift);
- if (lshift == 0)
- {
- emit_insn (gen_lshrsi3 (operands[0], operands[1], operands[3]));
- DONE;
- }
- operands[2] = GEN_INT (lshift);
- operands[4] = gen_reg_rtx (SImode);
-}
-")
-
-;; Block-move insns
-
-(define_expand "movstrqi"
- [(match_operand:BLK 0 "general_operand" "")
- (match_operand:BLK 1 "general_operand" "")
- (match_operand:SI 2 "" "")
- (match_operand:SI 3 "const_int_operand" "")]
- ""
- "
- if (INTVAL (operands[3]) != 4
- || GET_CODE (operands[2]) != CONST_INT
- || INTVAL (operands[2]) > 48)
- FAIL;
-
- thumb_expand_movstrqi (operands);
- DONE;
-")
-
-(define_insn "movmem12b"
- [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l"))
- (mem:SI (match_operand:SI 1 "register_operand" "+&l")))
- (set (mem:SI (plus:SI (match_dup 0) (const_int 4)))
- (mem:SI (plus:SI (match_dup 1) (const_int 4))))
- (set (mem:SI (plus:SI (match_dup 0) (const_int 8)))
- (mem:SI (plus:SI (match_dup 1) (const_int 8))))
- (set (match_dup 0) (plus:SI (match_dup 0) (const_int 12)))
- (set (match_dup 1) (plus:SI (match_dup 1) (const_int 12)))
- (clobber (match_scratch:SI 2 "=&l"))
- (clobber (match_scratch:SI 3 "=&l"))
- (clobber (match_scratch:SI 4 "=&l"))]
- ""
- "* return output_move_mem_multiple (3, operands);"
-[(set_attr "length" "4")])
-
-(define_insn "movmem8b"
- [(set (mem:SI (match_operand:SI 0 "register_operand" "+&l"))
- (mem:SI (match_operand:SI 1 "register_operand" "+&l")))
- (set (mem:SI (plus:SI (match_dup 0) (const_int 4)))
- (mem:SI (plus:SI (match_dup 1) (const_int 4))))
- (set (match_dup 0) (plus:SI (match_dup 0) (const_int 8)))
- (set (match_dup 1) (plus:SI (match_dup 1) (const_int 8)))
- (clobber (match_scratch:SI 2 "=&l"))
- (clobber (match_scratch:SI 3 "=&l"))]
- ""
- "* return output_move_mem_multiple (2, operands);"
-[(set_attr "length" "4")])
-
-;; Arithmetic insns
-
-(define_insn "negdi2"
- [(set (match_operand:DI 0 "register_operand" "=&l")
- (neg:DI (match_operand:DI 1 "register_operand" "l")))]
- ""
- "neg\\t%Q0, %Q1\;mov\\t%R0, #0\;sbc\\t%R0, %R1"
- [(set_attr "conds" "changed")
- (set_attr "length" "6")]
-)
-
-(define_insn "adddi3"
- [(set (match_operand:DI 0 "register_operand" "=l")
- (plus:DI (match_operand:DI 1 "register_operand" "%0")
- (match_operand:DI 2 "register_operand" "l")))]
- ""
- "add\\t%Q0, %Q0, %Q2\;adc\\t%R0, %R0, %R2"
-[(set_attr "conds" "changed")
- (set_attr "length" "4")])
-
-;; register group 'k' is a single register group containing only the stack
-;; register. Trying to reload it will always fail catastrophically,
-;; so never allow those alternatives to match if reloading is needed.
-(define_insn "addsi3"
- [(set (match_operand:SI 0 "register_operand" "=l,l,l,*r,*h,l,!k")
- (plus:SI (match_operand:SI 1 "register_operand" "%0,0,l,*0,*0,!k,!k")
- (match_operand:SI 2 "nonmemory_operand" "I,J,lL,*h,*r,!M,!O")))]
- ""
- "*
- static char *asms[] =
-{
- \"add\\t%0, %0, %2\",
- \"sub\\t%0, %0, #%n2\",
- \"add\\t%0, %1, %2\",
- \"add\\t%0, %0, %2\",
- \"add\\t%0, %0, %2\",
- \"add\\t%0, %1, %2\",
- \"add\\t%0, %1, %2\"
-};
- if (which_alternative == 2 && GET_CODE (operands[2]) == CONST_INT
- && INTVAL (operands[2]) < 0)
- return \"sub\\t%0, %1, #%n2\";
- return asms[which_alternative];
-")
-
-; reloading and elimination of the frame pointer can sometimes cause this
-; optimization to be missed.
-(define_peephole
- [(set (match_operand:SI 0 "register_operand" "=l")
- (match_operand:SI 1 "const_int_operand" "M"))
- (set (match_dup 0)
- (plus:SI (match_dup 0) (match_operand:SI 2 "register_operand" "k")))]
- "REGNO (operands[2]) == STACK_POINTER_REGNUM
- && (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) < 1024
- && (INTVAL (operands[1]) & 3) == 0"
- "add\\t%0, %2, %1")
-
-(define_insn "subdi3"
- [(set (match_operand:DI 0 "register_operand" "=l")
- (minus:DI (match_operand:DI 1 "register_operand" "0")
- (match_operand:DI 2 "register_operand" "l")))]
- ""
- "sub\\t%Q0, %Q0, %Q2\;sbc\\t%R0, %R0, %R2"
-[(set_attr "conds" "changed")
- (set_attr "length" "4")])
-
-(define_insn "subsi3"
- [(set (match_operand:SI 0 "register_operand" "=l")
- (minus:SI (match_operand:SI 1 "register_operand" "l")
- (match_operand:SI 2 "register_operand" "l")))]
- ""
- "sub\\t%0, %1, %2")
-
-;; We must ensure that one input matches the output, and that the other input
-;; does not match the output. Using 0 satisfies the first, and using &
-;; satisfies the second. Unfortunately, this fails when operands 1 and 2
-;; are the same, because reload will make operand 0 match operand 1 without
-;; realizing that this conflicts with operand 2. We fix this by adding another
-;; alternative to match this case, and then `reload' it ourselves. This
-;; alternative must come first.
-(define_insn "mulsi3"
- [(set (match_operand:SI 0 "register_operand" "=&l,&l,&l")
- (mult:SI (match_operand:SI 1 "register_operand" "%l,*h,0")
- (match_operand:SI 2 "register_operand" "l,l,l")))]
- ""
- "*
-{
- if (which_alternative < 2)
- return \"mov\\t%0, %1\;mul\\t%0, %0, %2\";
- else
- return \"mul\\t%0, %0, %2\";
-}"
- [(set_attr "length" "4,4,2")])
-
-(define_insn "negsi2"
- [(set (match_operand:SI 0 "register_operand" "=l")
- (neg:SI (match_operand:SI 1 "register_operand" "l")))]
- ""
- "neg\\t%0, %1")
-
-;; Logical insns
-
-(define_expand "andsi3"
- [(set (match_operand:SI 0 "register_operand" "")
- (and:SI (match_operand:SI 1 "register_operand" "")
- (match_operand:SI 2 "nonmemory_operand" "")))]
- ""
- "
- if (GET_CODE (operands[2]) != CONST_INT)
- operands[2] = force_reg (SImode, operands[2]);
- else
- {
- int i;
- if (((unsigned HOST_WIDE_INT) ~ INTVAL (operands[2])) < 256)
- {
- operands[2] = force_reg (SImode, GEN_INT (~INTVAL (operands[2])));
- emit_insn (gen_bicsi3 (operands[0], operands[2], operands[1]));
- DONE;
- }
-
- for (i = 9; i <= 31; i++)
- if ((((HOST_WIDE_INT) 1) << i) - 1 == INTVAL (operands[2]))
- {
- emit_insn (gen_extzv (operands[0], operands[1], GEN_INT (i),
- const0_rtx));
- DONE;
- }
- else if ((((HOST_WIDE_INT) 1) << i) - 1 == ~ INTVAL (operands[2]))
- {
- rtx shift = GEN_INT (i);
- rtx reg = gen_reg_rtx (SImode);
- emit_insn (gen_lshrsi3 (reg, operands[1], shift));
- emit_insn (gen_ashlsi3 (operands[0], reg, shift));
- DONE;
- }
-
- operands[2] = force_reg (SImode, operands[2]);
- }
-")
-
-(define_insn "*andsi3_insn"
- [(set (match_operand:SI 0 "register_operand" "=l")
- (and:SI (match_operand:SI 1 "register_operand" "%0")
- (match_operand:SI 2 "register_operand" "l")))]
- ""
- "and\\t%0, %0, %2")
-
-(define_insn "bicsi3"
- [(set (match_operand:SI 0 "register_operand" "=l")
- (and:SI (not:SI (match_operand:SI 1 "register_operand" "l"))
- (match_operand:SI 2 "register_operand" "0")))]
- ""
- "bic\\t%0, %0, %1")
-
-(define_insn "iorsi3"
- [(set (match_operand:SI 0 "register_operand" "=l")
- (ior:SI (match_operand:SI 1 "register_operand" "%0")
- (match_operand:SI 2 "register_operand" "l")))]
- ""
- "orr\\t%0, %0, %2")
-
-(define_insn "xorsi3"
- [(set (match_operand:SI 0 "register_operand" "=l")
- (xor:SI (match_operand:SI 1 "register_operand" "%0")
- (match_operand:SI 2 "register_operand" "l")))]
- ""
- "eor\\t%0, %0, %2")
-
-(define_insn "one_cmplsi2"
- [(set (match_operand:SI 0 "register_operand" "=l")
- (not:SI (match_operand:SI 1 "register_operand" "l")))]
- ""
- "mvn\\t%0, %1")
-
-;; Shift and rotation insns
-
-(define_insn "ashlsi3"
- [(set (match_operand:SI 0 "register_operand" "=l,l")
- (ashift:SI (match_operand:SI 1 "register_operand" "l,0")
- (match_operand:SI 2 "nonmemory_operand" "N,l")))]
- ""
- "@
- lsl\\t%0, %1, %2
- lsl\\t%0, %0, %2")
-
-(define_insn "ashrsi3"
- [(set (match_operand:SI 0 "register_operand" "=l,l")
- (ashiftrt:SI (match_operand:SI 1 "register_operand" "l,0")
- (match_operand:SI 2 "nonmemory_operand" "N,l")))]
- ""
- "@
- asr\\t%0, %1, %2
- asr\\t%0, %0, %2")
-
-(define_insn "lshrsi3"
- [(set (match_operand:SI 0 "register_operand" "=l,l")
- (lshiftrt:SI (match_operand:SI 1 "register_operand" "l,0")
- (match_operand:SI 2 "nonmemory_operand" "N,l")))]
- ""
- "@
- lsr\\t%0, %1, %2
- lsr\\t%0, %0, %2")
-
-(define_insn "rotrsi3"
- [(set (match_operand:SI 0 "register_operand" "=l")
- (rotatert:SI (match_operand:SI 1 "register_operand" "0")
- (match_operand:SI 2 "register_operand" "l")))]
- ""
- "ror\\t%0, %0, %2")
-
-;; Comparison insns
-
-(define_expand "cmpsi"
- [(set (cc0) (compare (match_operand:SI 0 "register_operand" "")
- (match_operand:SI 1 "nonmemory_operand" "")))]
- ""
- "
- if (GET_CODE (operands[1]) != REG && GET_CODE (operands[1]) != SUBREG)
- {
- if (GET_CODE (operands[1]) != CONST_INT
- || (unsigned HOST_WIDE_INT) (INTVAL (operands[1])) >= 256)
- {
- if (GET_CODE (operands[1]) != CONST_INT
- || INTVAL (operands[1]) < -255
- || INTVAL (operands[1]) > 0)
- operands[1] = force_reg (SImode, operands[1]);
- else
- {
- operands[1] = force_reg (SImode,
- GEN_INT (- INTVAL (operands[1])));
- emit_insn (gen_cmnsi (operands[0], operands[1]));
- DONE;
- }
- }
- }
-")
-
-(define_insn "*cmpsi_insn"
- [(set (cc0) (compare (match_operand:SI 0 "register_operand" "l,*r,*h")
- (match_operand:SI 1 "thumb_cmp_operand" "lI,*h,*r")))]
- ""
- "@
- cmp\\t%0, %1
- cmp\\t%0, %1
- cmp\\t%0, %1")
-
-(define_insn "tstsi"
- [(set (cc0) (match_operand:SI 0 "register_operand" "l"))]
- ""
- "cmp\\t%0, #0")
-
-(define_insn "cmnsi"
- [(set (cc0) (compare (match_operand:SI 0 "register_operand" "l")
- (neg:SI (match_operand:SI 1 "register_operand" "l"))))]
- ""
- "cmn\\t%0, %1")
-
-;; Jump insns
-
-(define_insn "jump"
- [(set (pc) (label_ref (match_operand 0 "" "")))]
- ""
- "*
- if (get_attr_length (insn) == 2)
- return \"b\\t%l0\";
- return \"bl\\t%l0\\t%@ far jump\";
-"[(set (attr "far_jump")
- (if_then_else (eq_attr "length" "4")
- (const_string "yes")
- (const_string "no")))
- (set (attr "length")
- (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2048))
- (le (minus (match_dup 0) (pc)) (const_int 2044)))
- (const_int 2)
- (const_int 4)))])
-
-
-(define_expand "beq"
- [(set (pc) (if_then_else (eq (cc0) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "")
-
-(define_expand "bne"
- [(set (pc) (if_then_else (ne (cc0) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "")
-
-(define_expand "bge"
- [(set (pc) (if_then_else (ge (cc0) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "")
-
-(define_expand "ble"
- [(set (pc) (if_then_else (le (cc0) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "")
-
-(define_expand "bgt"
- [(set (pc) (if_then_else (gt (cc0) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "")
-
-(define_expand "blt"
- [(set (pc) (if_then_else (lt (cc0) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "")
-
-(define_expand "bgeu"
- [(set (pc) (if_then_else (geu (cc0) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "")
-
-(define_expand "bleu"
- [(set (pc) (if_then_else (leu (cc0) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "")
-
-(define_expand "bgtu"
- [(set (pc) (if_then_else (gtu (cc0) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "")
-
-(define_expand "bltu"
- [(set (pc) (if_then_else (ltu (cc0) (const_int 0))
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "")
-
-(define_insn "*cond_branch"
- [(set (pc) (if_then_else (match_operator 1 "comparison_operator"
- [(cc0) (const_int 0)])
- (label_ref (match_operand 0 "" ""))
- (pc)))]
- ""
- "*
- switch (get_attr_length (insn))
- {
- case 2: return \"b%d1\\t%l0\\t%@cond_branch\";
- case 4: return \"b%D1\\t.LCB%=\;b\\t%l0\\t%@long jump\\n.LCB%=:\";
- default: return \"b%D1\\t.LCB%=\;bl\\t%l0\\t%@far jump\\n.LCB%=:\";
- }
-"[(set (attr "far_jump")
- (if_then_else (eq_attr "length" "6")
- (const_string "yes")
- (const_string "no")))
- (set (attr "length")
- (if_then_else
- (and (ge (minus (match_dup 0) (pc)) (const_int -252))
- (le (minus (match_dup 0) (pc)) (const_int 254)))
- (const_int 2)
- (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044))
- (le (minus (match_dup 0) (pc)) (const_int 2044)))
- (const_int 4)
- (const_int 6))))])
-
-(define_insn "*cond_branch_reversed"
- [(set (pc) (if_then_else (match_operator 1 "comparison_operator"
- [(cc0) (const_int 0)])
- (pc)
- (label_ref (match_operand 0 "" ""))))]
- ""
- "*
- switch (get_attr_length (insn))
- {
- case 2: return \"b%D1\\t%l0\\t%@cond_branch_reversed\";
- case 4: return \"b%d1\\t.LCBR%=\;b\\t%l0\\t%@long jump\\n.LCBR%=:\";
- default: return \"b%d1\\t.LCBR%=\;bl\\t%l0\\t%@far jump\\n.LCBR%=:\";
- }
- return \"\";
-"[(set (attr "far_jump")
- (if_then_else (eq_attr "length" "6")
- (const_string "yes")
- (const_string "no")))
- (set (attr "length")
- (if_then_else
- (and (ge (minus (match_dup 0) (pc)) (const_int -252))
- (le (minus (match_dup 0) (pc)) (const_int 254)))
- (const_int 2)
- (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044))
- (le (minus (match_dup 0) (pc)) (const_int 2044)))
- (const_int 4)
- (const_int 6))))])
-
-(define_insn "indirect_jump"
- [(set (pc) (match_operand:SI 0 "register_operand" "l*r"))]
- ""
- "mov\\tpc, %0")
-
-(define_insn "tablejump"
- [(set (pc) (match_operand:SI 0 "register_operand" "l*r"))
- (use (label_ref (match_operand 1 "" "")))]
- ""
- "mov\\tpc, %0")
-
-(define_insn "return"
- [(return)]
- "USE_RETURN"
- "* return output_return ();"
-[(set_attr "length" "18")])
-
-;; Call insns
-
-(define_expand "call"
- [(call (match_operand:SI 0 "memory_operand" "")
- (match_operand 1 "" ""))]
- ""
- "")
-
-(define_insn "*call_indirect"
- [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
- (match_operand 1 "" ""))]
- "! TARGET_CALLER_INTERWORKING"
- "bl\\t%__call_via_%0"
-[(set_attr "length" "4")])
-;; The non THUMB_INTERWORK, non TARGET_CALLER_INTERWORKING version
-;; used to be: "mov\\tlr,pc\;bx\\t%0", but the mov does not set
-;; the bottom bit of lr so that a function return (using bx)
-;; would switch back into ARM mode...
-
-(define_insn "*call_indirect_interwork"
- [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
- (match_operand 1 "" ""))]
- "TARGET_CALLER_INTERWORKING"
- "bl\\t%__interwork_call_via_%0"
-[(set_attr "length" "4")])
-
-(define_expand "call_value"
- [(set (match_operand 0 "" "")
- (call (match_operand 1 "memory_operand" "")
- (match_operand 2 "" "")))]
- ""
- "")
-
-(define_insn "*call_value_indirect"
- [(set (match_operand 0 "" "=l")
- (call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
- (match_operand 2 "" "")))]
- "! TARGET_CALLER_INTERWORKING"
- "bl\\t%__call_via_%1"
-[(set_attr "length" "4")])
-;; See comment for call_indirect pattern
-
-(define_insn "*call_value_indirect_interwork"
- [(set (match_operand 0 "" "=l")
- (call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
- (match_operand 2 "" "")))]
- "TARGET_CALLER_INTERWORKING"
- "bl\\t%__interwork_call_via_%1"
-[(set_attr "length" "4")])
-
-
-(define_insn "*call_insn"
- [(call (mem:SI (match_operand:SI 0 "" "X"))
- (match_operand:SI 1 "" ""))]
- "GET_CODE (operands[0]) == SYMBOL_REF"
- "bl\\t%a0"
-[(set_attr "length" "4")])
-
-(define_insn "*call_value_insn"
- [(set (match_operand 0 "register_operand" "=l")
- (call (mem:SI (match_operand 1 "" "X"))
- (match_operand 2 "" "")))]
- "GET_CODE (operands[1]) == SYMBOL_REF"
- "bl\\t%a1"
-[(set_attr "length" "4")])
-
-;; Untyped call not required, since all funcs return in r0
-
-;; Miscellaneous patterns
-
-(define_insn "nop"
- [(clobber (const_int 0))]
- ""
- "mov\\tr8, r8")
-
-(define_insn "blockage"
- [(unspec_volatile [(const_int 0)] 0)]
- ""
- ""
- [(set_attr "length" "0")])
-
-(define_expand "prologue"
- [(const_int 0)]
- ""
- "
- thumb_expand_prologue ();
- DONE;
-")
-
-(define_expand "epilogue"
- [(unspec_volatile [(return)] 1)]
- "! thumb_trivial_epilogue ()"
- "
- thumb_expand_epilogue ();
- emit_jump_insn (gen_rtx_UNSPEC_VOLATILE (VOIDmode,
- gen_rtvec (1, gen_rtx_RETURN (VOIDmode)), 1));
- DONE;
-")
-
-(define_insn "*epilogue_insns"
- [(unspec_volatile [(return)] 1)]
- ""
- "*
- return thumb_unexpanded_epilogue ();
-"
-[(set_attr "length" "42")])
-
-;; Special patterns for dealing with the constant pool
-
-(define_insn "consttable_4"
- [(unspec_volatile [(match_operand 0 "" "")] 2)]
- ""
- "*
-{
- making_const_table = TRUE;
- 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)]
- ""
- "*
-{
- making_const_table = TRUE;
- 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)]
- ""
- "*
- making_const_table = FALSE;
- return \"\";
-")
-
-(define_insn "align_4"
- [(unspec_volatile [(const_int 0)] 5)]
- ""
- "*
- extern void assemble_align ();
- assemble_align (32);
- return \"\";
-")
-
-/* 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 "register_operand" "=r")
- (unspec:SI [(match_operand 1 "" "")] 3))]
- "flag_pic"
- "ldr\\t%0, %a1")
-
-(define_insn "pic_add_dot_plus_four"
- [(set (match_operand:SI 0 "register_operand" "+r")
- (plus:SI (match_dup 0) (const (plus:SI (pc) (const_int 4)))))
- (use (label_ref (match_operand 1 "" "")))]
- "flag_pic"
- "*
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
- CODE_LABEL_NUMBER (operands[1]));
- return \"add\\t%0, %|pc\";
-")
-