📄 thumb.md
字号:
;; 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]); }")(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) { 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) { 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -