📄 v850.md
字号:
;; GCC machine description for NEC V850;; Copyright (C) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc.;; Contributed by Jeff Law (law@cygnus.com).;; 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.;; The original PO technology requires these to be ordered by speed,;; so that assigner will pick the fastest.;; See file "rtl.def" for documentation on define_insn, match_*, et. al.;; The V851 manual states that the instruction address space is 16M;;; the various branch/call instructions only have a 22bit offset (4M range).;;;; One day we'll probably need to handle calls to targets more than 4M;; away.;; The size of instructions in bytes.(define_attr "length" "" (const_int 4))(define_attr "long_calls" "yes,no" (const (if_then_else (symbol_ref "TARGET_LONG_CALLS") (const_string "yes") (const_string "no")))) ;; Types of instructions (for scheduling purposes).(define_attr "type" "load,mult,other" (const_string "other"));; Condition code settings.;; none - insn does not affect cc;; none_0hit - insn does not affect cc but it does modify operand 0;; This attribute is used to keep track of when operand 0 changes.;; See the description of NOTICE_UPDATE_CC for more info.;; set_znv - sets z,n,v to usable values; c is unknown.;; set_zn - sets z,n to usable values; v,c is unknown.;; compare - compare instruction;; clobber - value of cc is unknown(define_attr "cc" "none,none_0hit,set_zn,set_znv,compare,clobber" (const_string "clobber"));; Function units for the V850. As best as I can tell, there's;; a traditional memory load/use stall as well as a stall if;; the result of a multiply is used too early.;;(define_function_unit "memory" 1 0 (eq_attr "type" "load") 2 0)(define_function_unit "mult" 1 0 (eq_attr "type" "mult") 2 0);; ----------------------------------------------------------------------;; MOVE INSTRUCTIONS;; ----------------------------------------------------------------------;; movqi(define_expand "movqi" [(set (match_operand:QI 0 "general_operand" "") (match_operand:QI 1 "general_operand" ""))] "" "{ /* One of the ops has to be in a register or 0 */ if (!register_operand (operand0, QImode) && !reg_or_0_operand (operand1, QImode)) operands[1] = copy_to_mode_reg (QImode, operand1);}")(define_insn "*movqi_internal" [(set (match_operand:QI 0 "general_operand" "=r,r,r,Q,r,m,m") (match_operand:QI 1 "general_operand" "Jr,n,Q,Ir,m,r,I"))] "register_operand (operands[0], QImode) || reg_or_0_operand (operands[1], QImode)" "* return output_move_single (operands);" [(set_attr "length" "2,4,2,2,4,4,4") (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit") (set_attr "type" "other,other,load,other,load,other,other")]);; movhi(define_expand "movhi" [(set (match_operand:HI 0 "general_operand" "") (match_operand:HI 1 "general_operand" ""))] "" "{ /* One of the ops has to be in a register or 0 */ if (!register_operand (operand0, HImode) && !reg_or_0_operand (operand1, HImode)) operands[1] = copy_to_mode_reg (HImode, operand1);}")(define_insn "*movhi_internal" [(set (match_operand:HI 0 "general_operand" "=r,r,r,Q,r,m,m") (match_operand:HI 1 "general_operand" "Jr,n,Q,Ir,m,r,I"))] "register_operand (operands[0], HImode) || reg_or_0_operand (operands[1], HImode)" "* return output_move_single (operands);" [(set_attr "length" "2,4,2,2,4,4,4") (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit") (set_attr "type" "other,other,load,other,load,other,other")]);; movsi and helpers(define_insn "*movsi_high" [(set (match_operand:SI 0 "register_operand" "=r") (high:SI (match_operand 1 "" "")))] "" "movhi hi(%1),%.,%0" [(set_attr "length" "4") (set_attr "cc" "none_0hit") (set_attr "type" "other")])(define_insn "*movsi_lo" [(set (match_operand:SI 0 "register_operand" "=r") (lo_sum:SI (match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "immediate_operand" "i")))] "" "movea lo(%2),%1,%0" [(set_attr "length" "4") (set_attr "cc" "none_0hit") (set_attr "type" "other")])(define_expand "movsi" [(set (match_operand:SI 0 "general_operand" "") (match_operand:SI 1 "general_operand" ""))] "" "{ /* One of the ops has to be in a register or 0 */ if (!register_operand (operand0, SImode) && !reg_or_0_operand (operand1, SImode)) operands[1] = copy_to_mode_reg (SImode, operand1); /* Some constants, as well as symbolic operands must be done with HIGH & LO_SUM patterns. */ if (CONSTANT_P (operands[1]) && GET_CODE (operands[1]) != HIGH && ! TARGET_V850E && !special_symbolref_operand (operands[1], VOIDmode) && !(GET_CODE (operands[1]) == CONST_INT && (CONST_OK_FOR_J (INTVAL (operands[1])) || CONST_OK_FOR_K (INTVAL (operands[1])) || CONST_OK_FOR_L (INTVAL (operands[1]))))) { rtx temp; if (reload_in_progress || reload_completed) temp = operands[0]; else temp = gen_reg_rtx (SImode); emit_insn (gen_rtx_SET (SImode, temp, gen_rtx_HIGH (SImode, operand1))); emit_insn (gen_rtx_SET (SImode, operand0, gen_rtx_LO_SUM (SImode, temp, operand1))); DONE; }}");; This is the same as the following pattern, except that it includes;; support for arbitrary 32 bit immediates.;; ??? This always loads addresses using hilo. If the only use of this address;; was in a load/store, then we would get smaller code if we only loaded the;; upper part with hi, and then put the lower part in the load/store insn.(define_insn "*movsi_internal_v850e" [(set (match_operand:SI 0 "general_operand" "=r,r,r,r,Q,r,r,m,m,r") (match_operand:SI 1 "general_operand" "Jr,K,L,Q,Ir,m,R,r,I,i"))] "TARGET_V850E && (register_operand (operands[0], SImode) || reg_or_0_operand (operands[1], SImode))" "* return output_move_single (operands);" [(set_attr "length" "2,4,4,2,2,4,4,4,4,6") (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit") (set_attr "type" "other,other,other,load,other,load,other,other,other,other")])(define_insn "*movsi_internal" [(set (match_operand:SI 0 "general_operand" "=r,r,r,r,Q,r,r,m,m") (match_operand:SI 1 "movsi_source_operand" "Jr,K,L,Q,Ir,m,R,r,I"))] "register_operand (operands[0], SImode) || reg_or_0_operand (operands[1], SImode)" "* return output_move_single (operands);" [(set_attr "length" "2,4,4,2,2,4,4,4,4") (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit") (set_attr "type" "other,other,other,load,other,load,other,other,other")])(define_expand "movdi" [(set (match_operand:DI 0 "general_operand" "") (match_operand:DI 1 "general_operand" ""))] "" "{ /* One of the ops has to be in a register or 0 */ if (!register_operand (operand0, DImode) && !reg_or_0_operand (operand1, DImode)) operands[1] = copy_to_mode_reg (DImode, operand1);}")(define_insn "*movdi_internal" [(set (match_operand:DI 0 "general_operand" "=r,r,r,r,r,m,m,r") (match_operand:DI 1 "general_operand" "Jr,K,L,i,m,r,IG,iF"))] "register_operand (operands[0], DImode) || reg_or_0_operand (operands[1], DImode)" "* return output_move_double (operands);" [(set_attr "length" "4,8,8,16,8,8,8,16") (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit") (set_attr "type" "other,other,other,other,load,other,other,other")])(define_expand "movsf" [(set (match_operand:SF 0 "general_operand" "") (match_operand:SF 1 "general_operand" ""))] "" "{ /* One of the ops has to be in a register or 0 */ if (!register_operand (operand0, SFmode) && !reg_or_0_operand (operand1, SFmode)) operands[1] = copy_to_mode_reg (SFmode, operand1);}")(define_insn "*movsf_internal" [(set (match_operand:SF 0 "general_operand" "=r,r,r,r,r,Q,r,m,m,r") (match_operand:SF 1 "general_operand" "Jr,K,L,n,Q,Ir,m,r,IG,iF"))] "register_operand (operands[0], SFmode) || reg_or_0_operand (operands[1], SFmode)" "* return output_move_single (operands);" [(set_attr "length" "2,4,4,8,2,2,4,4,4,8") (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit") (set_attr "type" "other,other,other,other,load,other,load,other,other,other")])(define_expand "movdf" [(set (match_operand:DF 0 "general_operand" "") (match_operand:DF 1 "general_operand" ""))] "" "{ /* One of the ops has to be in a register or 0 */ if (!register_operand (operand0, DFmode) && !reg_or_0_operand (operand1, DFmode)) operands[1] = copy_to_mode_reg (DFmode, operand1);}")(define_insn "*movdf_internal" [(set (match_operand:DF 0 "general_operand" "=r,r,r,r,r,m,m,r") (match_operand:DF 1 "general_operand" "Jr,K,L,i,m,r,IG,iF"))] "register_operand (operands[0], DFmode) || reg_or_0_operand (operands[1], DFmode)" "* return output_move_double (operands);" [(set_attr "length" "4,8,8,16,8,8,8,16") (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit") (set_attr "type" "other,other,other,other,load,other,other,other")]);; ----------------------------------------------------------------------;; TEST INSTRUCTIONS;; ----------------------------------------------------------------------(define_insn "*v850_tst1" [(set (cc0) (zero_extract:SI (match_operand:QI 0 "memory_operand" "m") (const_int 1) (match_operand:QI 1 "const_int_operand" "n")))] "" "tst1 %1,%0" [(set_attr "length" "4") (set_attr "cc" "clobber")]);; This replaces ld.b;sar;andi with tst1;setf nz.;; ??? The zero_extract sets the Z bit to the opposite of what one would;; expect. This perhaps should be wrapped in a (eq: X (const_int 0)).(define_split [(set (match_operand:SI 0 "register_operand" "") (zero_extract:SI (match_operand:QI 1 "memory_operand" "") (const_int 1) (match_operand 2 "const_int_operand" "")))] "" [(set (cc0) (zero_extract:SI (match_dup 1) (const_int 1) (match_dup 2))) (set (match_dup 0) (ne:SI (cc0) (const_int 0)))])(define_insn "tstsi" [(set (cc0) (match_operand:SI 0 "register_operand" "r"))] "" "cmp %.,%0" [(set_attr "length" "2") (set_attr "cc" "set_znv")])(define_insn "cmpsi" [(set (cc0) (compare (match_operand:SI 0 "register_operand" "r,r") (match_operand:SI 1 "reg_or_int5_operand" "r,J")))] "" "@ cmp %1,%0 cmp %1,%0" [(set_attr "length" "2,2") (set_attr "cc" "compare")]);; ----------------------------------------------------------------------;; ADD INSTRUCTIONS;; ----------------------------------------------------------------------(define_insn "addsi3" [(set (match_operand:SI 0 "register_operand" "=r,r,r") (plus:SI (match_operand:SI 1 "register_operand" "%0,r,r") (match_operand:SI 2 "nonmemory_operand" "rJ,K,U")))] "" "@ add %2,%0 addi %2,%1,%0 addi %O2(%P2),%1,%0" [(set_attr "length" "2,4,4") (set_attr "cc" "set_zn,set_zn,set_zn")]);; ----------------------------------------------------------------------;; SUBTRACT INSTRUCTIONS;; ----------------------------------------------------------------------(define_insn "subsi3" [(set (match_operand:SI 0 "register_operand" "=r,r") (minus:SI (match_operand:SI 1 "register_operand" "0,r") (match_operand:SI 2 "register_operand" "r,0")))] "" "@ sub %2,%0 subr %1,%0" [(set_attr "length" "2,2") (set_attr "cc" "set_zn")])(define_insn "negsi2" [(set (match_operand:SI 0 "register_operand" "=r") (neg:SI (match_operand:SI 1 "register_operand" "0")))] "" "subr %.,%0" [(set_attr "length" "2") (set_attr "cc" "set_zn")]);; ----------------------------------------------------------------------;; MULTIPLY INSTRUCTIONS;; ----------------------------------------------------------------------(define_expand "mulhisi3" [(set (match_operand:SI 0 "register_operand" "") (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "")) (sign_extend:SI (match_operand:HI 2 "nonmemory_operand" ""))))] "" "")(define_insn "*mulhisi3_internal1" [(set (match_operand:SI 0 "register_operand" "=r") (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0")) (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))] "" "mulh %2,%0" [(set_attr "length" "2") (set_attr "cc" "none_0hit") (set_attr "type" "mult")]);; ??? Sign extending constants isn't valid. Fix?(define_insn "*mulhisi3_internal2" [(set (match_operand:SI 0 "register_operand" "=r,r") (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0,r")) (sign_extend:SI (match_operand 2 "const_int_operand" "J,K"))))] "" "@ mulh %2,%0 mulhi %2,%1,%0" [(set_attr "length" "2,4") (set_attr "cc" "none_0hit,none_0hit") (set_attr "type" "mult")]);; ??? The scheduling info is probably wrong.;; ??? This instruction can also generate the 32 bit highpart, but using it;; may increase code size counter to the desired result.;; ??? This instructions can also give a DImode result.;; ??? There is unsigned version, but it matters only for the DImode/highpart;; results.(define_insn "mulsi3" [(set (match_operand:SI 0 "register_operand" "=r") (mult:SI (match_operand:SI 1 "register_operand" "%0") (match_operand:SI 2 "reg_or_int9_operand" "rO")))] "TARGET_V850E" "mul %2,%1,%." [(set_attr "length" "4") (set_attr "cc" "none_0hit") (set_attr "type" "mult")]);; ----------------------------------------------------------------------;; DIVIDE INSTRUCTIONS;; ----------------------------------------------------------------------;; ??? These insns do set the Z/N condition codes, except that they are based;; on only one of the two results, so it doesn't seem to make sense to use;; them.;; ??? The scheduling info is probably wrong.(define_insn "divmodsi4" [(set (match_operand:SI 0 "register_operand" "=r") (div:SI (match_operand:SI 1 "register_operand" "0") (match_operand:SI 2 "register_operand" "r"))) (set (match_operand:SI 3 "register_operand" "=r") (mod:SI (match_dup 1) (match_dup 2)))] "TARGET_V850E" "div %2,%0,%3" [(set_attr "length" "4") (set_attr "cc" "clobber") (set_attr "type" "other")]) (define_insn "udivmodsi4" [(set (match_operand:SI 0 "register_operand" "=r") (udiv:SI (match_operand:SI 1 "register_operand" "0") (match_operand:SI 2 "register_operand" "r"))) (set (match_operand:SI 3 "register_operand" "=r") (umod:SI (match_dup 1) (match_dup 2)))] "TARGET_V850E" "divu %2,%0,%3" [(set_attr "length" "4") (set_attr "cc" "clobber") (set_attr "type" "other")]) ;; ??? There is a 2 byte instruction for generating only the quotient.;; However, it isn't clear how to compute the length field correctly.(define_insn "divmodhi4" [(set (match_operand:HI 0 "register_operand" "=r") (div:HI (match_operand:HI 1 "register_operand" "0") (match_operand:HI 2 "register_operand" "r"))) (set (match_operand:HI 3 "register_operand" "=r") (mod:HI (match_dup 1) (match_dup 2)))] "TARGET_V850E" "divh %2,%0,%3" [(set_attr "length" "4") (set_attr "cc" "clobber") (set_attr "type" "other")]);; Half-words are sign-extended by default, so we must zero extend to a word;; here before doing the divide.(define_insn "udivmodhi4" [(set (match_operand:HI 0 "register_operand" "=r") (udiv:HI (match_operand:HI 1 "register_operand" "0") (match_operand:HI 2 "register_operand" "r"))) (set (match_operand:HI 3 "register_operand" "=r") (umod:HI (match_dup 1) (match_dup 2)))] "TARGET_V850E" "zxh %0 ; divhu %2,%0,%3" [(set_attr "length" "4") (set_attr "cc" "clobber") (set_attr "type" "other")]);; ----------------------------------------------------------------------;; AND INSTRUCTIONS;; ----------------------------------------------------------------------(define_insn "*v850_clr1_1"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -