NetBSD/gnu/dist/gcc/config/v850/v850.md

1274 lines
35 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;; GCC machine description for NEC V850
;; Copyright (C) 1996, 1997 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 200))
;; 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
&& !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 high;
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;
}
}")
(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")])
;; ----------------------------------------------------------------------
;; AND INSTRUCTIONS
;; ----------------------------------------------------------------------
(define_insn "*v850_clr1_1"
[(set (match_operand:QI 0 "memory_operand" "=m")
(subreg:QI
(and:SI (subreg:SI (match_dup 0) 0)
(match_operand:QI 1 "not_power_of_two_operand" "")) 0))]
""
"*
{
rtx xoperands[2];
xoperands[0] = operands[0];
xoperands[1] = GEN_INT (~INTVAL (operands[1]) & 0xff);
output_asm_insn (\"clr1 %M1,%0\", xoperands);
return \"\";
}"
[(set_attr "length" "4")
(set_attr "cc" "clobber")])
(define_insn "*v850_clr1_2"
[(set (match_operand:HI 0 "memory_operand" "=m")
(subreg:HI
(and:SI (subreg:SI (match_dup 0) 0)
(match_operand:HI 1 "not_power_of_two_operand" "")) 0))]
""
"*
{
int log2 = exact_log2 (~INTVAL (operands[1]) & 0xffff);
rtx xoperands[2];
xoperands[0] = gen_rtx (MEM, QImode,
plus_constant (XEXP (operands[0], 0), log2 / 8));
xoperands[1] = GEN_INT (log2 % 8);
output_asm_insn (\"clr1 %1,%0\", xoperands);
return \"\";
}"
[(set_attr "length" "4")
(set_attr "cc" "clobber")])
(define_insn "*v850_clr1_3"
[(set (match_operand:SI 0 "memory_operand" "=m")
(and:SI (match_dup 0)
(match_operand:SI 1 "not_power_of_two_operand" "")))]
""
"*
{
int log2 = exact_log2 (~INTVAL (operands[1]) & 0xffffffff);
rtx xoperands[2];
xoperands[0] = gen_rtx (MEM, QImode,
plus_constant (XEXP (operands[0], 0), log2 / 8));
xoperands[1] = GEN_INT (log2 % 8);
output_asm_insn (\"clr1 %1,%0\", xoperands);
return \"\";
}"
[(set_attr "length" "4")
(set_attr "cc" "clobber")])
(define_insn "andsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r")
(and:SI (match_operand:SI 1 "register_operand" "%0,0,r")
(match_operand:SI 2 "nonmemory_operand" "r,I,M")))]
""
"@
and %2,%0
and %.,%0
andi %2,%1,%0"
[(set_attr "length" "2,2,4")
(set_attr "cc" "set_znv")])
;; ----------------------------------------------------------------------
;; OR INSTRUCTIONS
;; ----------------------------------------------------------------------
(define_insn "*v850_set1_1"
[(set (match_operand:QI 0 "memory_operand" "=m")
(subreg:QI (ior:SI (subreg:SI (match_dup 0) 0)
(match_operand 1 "power_of_two_operand" "")) 0))]
""
"set1 %M1,%0"
[(set_attr "length" "4")
(set_attr "cc" "clobber")])
(define_insn "*v850_set1_2"
[(set (match_operand:HI 0 "memory_operand" "=m")
(subreg:HI (ior:SI (subreg:SI (match_dup 0) 0)
(match_operand 1 "power_of_two_operand" "")) 0))]
""
"*
{
int log2 = exact_log2 (INTVAL (operands[1]));
if (log2 < 8)
return \"set1 %M1,%0\";
else
{
rtx xoperands[2];
xoperands[0] = gen_rtx (MEM, QImode,
plus_constant (XEXP (operands[0], 0), log2 / 8));
xoperands[1] = GEN_INT (log2 % 8);
output_asm_insn (\"set1 %1,%0\", xoperands);
}
return \"\";
}"
[(set_attr "length" "4")
(set_attr "cc" "clobber")])
(define_insn "*v850_set1_3"
[(set (match_operand:SI 0 "memory_operand" "=m")
(ior:SI (match_dup 0)
(match_operand 1 "power_of_two_operand" "")))]
""
"*
{
int log2 = exact_log2 (INTVAL (operands[1]));
if (log2 < 8)
return \"set1 %M1,%0\";
else
{
rtx xoperands[2];
xoperands[0] = gen_rtx (MEM, QImode,
plus_constant (XEXP (operands[0], 0), log2 / 8));
xoperands[1] = GEN_INT (log2 % 8);
output_asm_insn (\"set1 %1,%0\", xoperands);
}
return \"\";
}"
[(set_attr "length" "4")
(set_attr "cc" "clobber")])
(define_insn "iorsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r")
(ior:SI (match_operand:SI 1 "register_operand" "%0,0,r")
(match_operand:SI 2 "nonmemory_operand" "r,I,M")))]
""
"@
or %2,%0
or %.,%0
ori %2,%1,%0"
[(set_attr "length" "2,2,4")
(set_attr "cc" "set_znv")])
;; ----------------------------------------------------------------------
;; XOR INSTRUCTIONS
;; ----------------------------------------------------------------------
(define_insn "*v850_not1_1"
[(set (match_operand:QI 0 "memory_operand" "=m")
(subreg:QI (xor:SI (subreg:SI (match_dup 0) 0)
(match_operand 1 "power_of_two_operand" "")) 0))]
""
"not1 %M1,%0"
[(set_attr "length" "4")
(set_attr "cc" "clobber")])
(define_insn "*v850_not1_2"
[(set (match_operand:HI 0 "memory_operand" "=m")
(subreg:HI (xor:SI (subreg:SI (match_dup 0) 0)
(match_operand 1 "power_of_two_operand" "")) 0))]
""
"*
{
int log2 = exact_log2 (INTVAL (operands[1]));
if (log2 < 8)
return \"not1 %M1,%0\";
else
{
rtx xoperands[2];
xoperands[0] = gen_rtx (MEM, QImode,
plus_constant (XEXP (operands[0], 0), log2 / 8));
xoperands[1] = GEN_INT (log2 % 8);
output_asm_insn (\"not1 %1,%0\", xoperands);
}
return \"\";
}"
[(set_attr "length" "4")
(set_attr "cc" "clobber")])
(define_insn "*v850_not1_3"
[(set (match_operand:SI 0 "memory_operand" "=m")
(xor:SI (match_dup 0)
(match_operand 1 "power_of_two_operand" "")))]
""
"*
{
int log2 = exact_log2 (INTVAL (operands[1]));
if (log2 < 8)
return \"not1 %M1,%0\";
else
{
rtx xoperands[2];
xoperands[0] = gen_rtx (MEM, QImode,
plus_constant (XEXP (operands[0], 0), log2 / 8));
xoperands[1] = GEN_INT (log2 % 8);
output_asm_insn (\"not1 %1,%0\", xoperands);
}
return \"\";
}"
[(set_attr "length" "4")
(set_attr "cc" "clobber")])
(define_insn "xorsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r,r")
(xor:SI (match_operand:SI 1 "register_operand" "%0,0,r")
(match_operand:SI 2 "nonmemory_operand" "r,I,M")))]
""
"@
xor %2,%0
xor %.,%0
xori %2,%1,%0"
[(set_attr "length" "2,2,4")
(set_attr "cc" "set_znv")])
;; ----------------------------------------------------------------------
;; NOT INSTRUCTIONS
;; ----------------------------------------------------------------------
(define_insn "one_cmplsi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(not:SI (match_operand:SI 1 "register_operand" "r")))]
""
"not %1,%0"
[(set_attr "length" "2")
(set_attr "cc" "set_znv")])
;; -----------------------------------------------------------------
;; BIT FIELDS
;; -----------------------------------------------------------------
;; ??? Is it worth defining insv and extv for the V850 series?!?
;; An insv pattern would be useful, but does not get used because
;; store_bit_field never calls insv when storing a constant value into a
;; single-bit bitfield.
;; extv/extzv patterns would be useful, but do not get used because
;; optimize_bitfield_compare in fold-const usually converts single
;; bit extracts into an AND with a mask.
;; -----------------------------------------------------------------
;; Scc INSTRUCTIONS
;; -----------------------------------------------------------------
(define_insn "sle"
[(set (match_operand:SI 0 "register_operand" "=r")
(le:SI (cc0) (const_int 0)))]
""
"*
{
if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0)
return 0;
return \"setf le,%0\";
}"
[(set_attr "length" "4")
(set_attr "cc" "none_0hit")])
(define_insn "sleu"
[(set (match_operand:SI 0 "register_operand" "=r")
(leu:SI (cc0) (const_int 0)))]
""
"setf nh,%0"
[(set_attr "length" "4")
(set_attr "cc" "none_0hit")])
(define_insn "sge"
[(set (match_operand:SI 0 "register_operand" "=r")
(ge:SI (cc0) (const_int 0)))]
""
"*
{
if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0)
return 0;
return \"setf ge,%0\";
}"
[(set_attr "length" "4")
(set_attr "cc" "none_0hit")])
(define_insn "sgeu"
[(set (match_operand:SI 0 "register_operand" "=r")
(geu:SI (cc0) (const_int 0)))]
""
"setf nl,%0"
[(set_attr "length" "4")
(set_attr "cc" "none_0hit")])
(define_insn "slt"
[(set (match_operand:SI 0 "register_operand" "=r")
(lt:SI (cc0) (const_int 0)))]
""
"*
{
if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0)
return 0;
return \"setf lt,%0\";
}"
[(set_attr "length" "4")
(set_attr "cc" "none_0hit")])
(define_insn "sltu"
[(set (match_operand:SI 0 "register_operand" "=r")
(ltu:SI (cc0) (const_int 0)))]
""
"setf l,%0"
[(set_attr "length" "4")
(set_attr "cc" "none_0hit")])
(define_insn "sgt"
[(set (match_operand:SI 0 "register_operand" "=r")
(gt:SI (cc0) (const_int 0)))]
""
"*
{
if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0)
return 0;
return \"setf gt,%0\";
}"
[(set_attr "length" "4")
(set_attr "cc" "none_0hit")])
(define_insn "sgtu"
[(set (match_operand:SI 0 "register_operand" "=r")
(gtu:SI (cc0) (const_int 0)))]
""
"setf h,%0"
[(set_attr "length" "4")
(set_attr "cc" "none_0hit")])
(define_insn "seq"
[(set (match_operand:SI 0 "register_operand" "=r")
(eq:SI (cc0) (const_int 0)))]
""
"setf z,%0"
[(set_attr "length" "4")
(set_attr "cc" "none_0hit")])
(define_insn "sne"
[(set (match_operand:SI 0 "register_operand" "=r")
(ne:SI (cc0) (const_int 0)))]
""
"setf nz,%0"
[(set_attr "length" "4")
(set_attr "cc" "none_0hit")])
;; ----------------------------------------------------------------------
;; JUMP INSTRUCTIONS
;; ----------------------------------------------------------------------
;; Conditional jump instructions
(define_expand "ble"
[(set (pc)
(if_then_else (le (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 "bge"
[(set (pc)
(if_then_else (ge (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 "blt"
[(set (pc)
(if_then_else (lt (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_expand "bgt"
[(set (pc)
(if_then_else (gt (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 "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_insn "*branch_normal"
[(set (pc)
(if_then_else (match_operator 1 "comparison_operator"
[(cc0) (const_int 0)])
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"*
{
if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0
&& (GET_CODE (operands[1]) == GT
|| GET_CODE (operands[1]) == GE
|| GET_CODE (operands[1]) == LE
|| GET_CODE (operands[1]) == LT))
return 0;
if (get_attr_length (insn) == 2)
return \"b%b1 %l0\";
else
return \"b%B1 .+6\;jr %l0\";
}"
[(set (attr "length")
(if_then_else (lt (abs (minus (match_dup 0) (pc)))
(const_int 256))
(const_int 2)
(const_int 6)))
(set_attr "cc" "none")])
(define_insn "*branch_invert"
[(set (pc)
(if_then_else (match_operator 1 "comparison_operator"
[(cc0) (const_int 0)])
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"*
{
if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0
&& (GET_CODE (operands[1]) == GT
|| GET_CODE (operands[1]) == GE
|| GET_CODE (operands[1]) == LE
|| GET_CODE (operands[1]) == LT))
return 0;
if (get_attr_length (insn) == 2)
return \"b%B1 %l0\";
else
return \"b%b1 .+6\;jr %l0\";
}"
[(set (attr "length")
(if_then_else (lt (abs (minus (match_dup 0) (pc)))
(const_int 256))
(const_int 2)
(const_int 6)))
(set_attr "cc" "none")])
;; Unconditional and other jump instructions.
(define_insn "jump"
[(set (pc)
(label_ref (match_operand 0 "" "")))]
""
"*
{
if (get_attr_length (insn) == 2)
return \"br %0\";
else
return \"jr %0\";
}"
[(set (attr "length")
(if_then_else (lt (abs (minus (match_dup 0) (pc)))
(const_int 256))
(const_int 2)
(const_int 4)))
(set_attr "cc" "none")])
(define_insn "indirect_jump"
[(set (pc) (match_operand:SI 0 "register_operand" "r"))]
""
"jmp %0"
[(set_attr "length" "2")
(set_attr "cc" "none")])
(define_insn "tablejump"
[(set (pc) (match_operand:SI 0 "register_operand" "r"))
(use (label_ref (match_operand 1 "" "")))]
""
"jmp %0"
[(set_attr "length" "2")
(set_attr "cc" "none")])
(define_expand "casesi"
[(match_operand:SI 0 "register_operand" "")
(match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "register_operand" "")
(match_operand 3 "" "") (match_operand 4 "" "")]
""
"
{
rtx reg = gen_reg_rtx (SImode);
rtx tableaddress = gen_reg_rtx (SImode);
rtx mem;
/* Subtract the lower bound from the index. */
emit_insn (gen_subsi3 (reg, operands[0], operands[1]));
/* Compare the result against the number of table entries. */
emit_insn (gen_cmpsi (reg, operands[2]));
/* Branch to the default label if out of range of the table. */
emit_jump_insn (gen_bgtu (operands[4]));
/* Shift index for the table array access. */
emit_insn (gen_ashlsi3 (reg, reg, GEN_INT (TARGET_BIG_SWITCH ? 2 : 1)));
/* Load the table address into a pseudo. */
emit_insn (gen_movsi (tableaddress,
gen_rtx (LABEL_REF, VOIDmode, operands[3])));
/* Add the table address to the index. */
emit_insn (gen_addsi3 (reg, reg, tableaddress));
/* Load the table entry. */
mem = gen_rtx (MEM, CASE_VECTOR_MODE, reg);
RTX_UNCHANGING_P (mem);
if (! TARGET_BIG_SWITCH)
{
rtx reg2 = gen_reg_rtx (HImode);
emit_insn (gen_movhi (reg2, mem));
emit_insn (gen_extendhisi2 (reg, reg2));
}
else
emit_insn (gen_movsi (reg, mem));
/* Add the table address. */
emit_insn (gen_addsi3 (reg, reg, tableaddress));
/* Branch to the switch label. */
emit_jump_insn (gen_tablejump (reg, operands[3]));
DONE;
}")
;; Call subroutine with no return value.
(define_expand "call"
[(call (match_operand:QI 0 "general_operand" "")
(match_operand:SI 1 "general_operand" ""))]
""
"
{
if (! call_address_operand (XEXP (operands[0], 0))
|| TARGET_LONG_CALLS)
XEXP (operands[0], 0) = force_reg (SImode, XEXP (operands[0], 0));
emit_call_insn (gen_call_internal (XEXP (operands[0], 0), operands[1]));
DONE;
}")
(define_insn "call_internal"
[(call (mem:QI (match_operand:SI 0 "call_address_operand" "S,r"))
(match_operand:SI 1 "general_operand" "g,g"))
(clobber (reg:SI 31))]
""
"@
jarl %0,r31
jarl .+4,r31\\n\\tadd 4,r31\\n\\tjmp %0"
[(set_attr "length" "4,8")])
;; Call subroutine, returning value in operand 0
;; (which must be a hard register).
(define_expand "call_value"
[(set (match_operand 0 "" "")
(call (match_operand:QI 1 "general_operand" "")
(match_operand:SI 2 "general_operand" "")))]
""
"
{
if (! call_address_operand (XEXP (operands[1], 0))
|| TARGET_LONG_CALLS)
XEXP (operands[1], 0) = force_reg (SImode, XEXP (operands[1], 0));
emit_call_insn (gen_call_value_internal (operands[0],
XEXP (operands[1], 0),
operands[2]));
DONE;
}")
(define_insn "call_value_internal"
[(set (match_operand 0 "" "=r,r")
(call (mem:QI (match_operand:SI 1 "call_address_operand" "S,r"))
(match_operand:SI 2 "general_operand" "g,g")))
(clobber (reg:SI 31))]
""
"@
jarl %1,r31
jarl .+4,r31\\n\\tadd 4,r31\\n\\tjmp %1"
[(set_attr "length" "4,8")])
(define_insn "nop"
[(const_int 0)]
""
"nop"
[(set_attr "length" "2")
(set_attr "cc" "none")])
;; ----------------------------------------------------------------------
;; EXTEND INSTRUCTIONS
;; ----------------------------------------------------------------------
(define_insn "zero_extendhisi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(zero_extend:SI
(match_operand:HI 1 "register_operand" "r")))]
""
"andi 65535,%1,%0"
[(set_attr "length" "4")
(set_attr "cc" "set_znv")])
(define_insn "zero_extendqisi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(zero_extend:SI
(match_operand:QI 1 "register_operand" "r")))]
""
"andi 255,%1,%0"
[(set_attr "length" "4")
(set_attr "cc" "set_znv")])
;;- sign extension instructions
;; ??? This is missing a sign extend from memory pattern to match the ld.h
;; instruction.
(define_expand "extendhisi2"
[(set (match_dup 2)
(ashift:SI (match_operand:HI 1 "register_operand" "")
(const_int 16)))
(set (match_operand:SI 0 "register_operand" "")
(ashiftrt:SI (match_dup 2)
(const_int 16)))]
""
"
{
operands[1] = gen_lowpart (SImode, operands[1]);
operands[2] = gen_reg_rtx (SImode);
}")
;; ??? This is missing a sign extend from memory pattern to match the ld.b
;; instruction.
(define_expand "extendqisi2"
[(set (match_dup 2)
(ashift:SI (match_operand:QI 1 "register_operand" "")
(const_int 24)))
(set (match_operand:SI 0 "register_operand" "")
(ashiftrt:SI (match_dup 2)
(const_int 24)))]
""
"
{
operands[1] = gen_lowpart (SImode, operands[1]);
operands[2] = gen_reg_rtx (SImode);
}")
;; ----------------------------------------------------------------------
;; SHIFTS
;; ----------------------------------------------------------------------
(define_insn "ashlsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(ashift:SI
(match_operand:SI 1 "register_operand" "0,0")
(match_operand:SI 2 "nonmemory_operand" "r,N")))]
""
"@
shl %2,%0
shl %2,%0"
[(set_attr "length" "4,2")
(set_attr "cc" "set_znv")])
(define_insn "lshrsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(lshiftrt:SI
(match_operand:SI 1 "register_operand" "0,0")
(match_operand:SI 2 "nonmemory_operand" "r,N")))]
""
"@
shr %2,%0
shr %2,%0"
[(set_attr "length" "4,2")
(set_attr "cc" "set_znv")])
(define_insn "ashrsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(ashiftrt:SI
(match_operand:SI 1 "register_operand" "0,0")
(match_operand:SI 2 "nonmemory_operand" "r,N")))]
""
"@
sar %2,%0
sar %2,%0"
[(set_attr "length" "4,2")
(set_attr "cc" "set_znv")])
;; ----------------------------------------------------------------------
;; PROLOGUE/EPILOGUE
;; ----------------------------------------------------------------------
(define_expand "prologue"
[(const_int 0)]
""
"expand_prologue (); DONE;")
(define_expand "epilogue"
[(return)]
""
"
{
/* Try to use the trivial return first. Else use the
full epilogue. */
if (0)
emit_jump_insn (gen_return ());
else
expand_epilogue ();
DONE;
}")
(define_insn "return"
[(return)]
"reload_completed && compute_frame_size (get_frame_size (), (long *)0) == 0"
"jmp [r31]"
[(set_attr "length" "2")
(set_attr "cc" "none")])
(define_insn "return_internal"
[(return)
(use (reg:SI 31))]
""
"jmp [r31]"
[(set_attr "length" "2")
(set_attr "cc" "none")])
;; ----------------------------------------------------------------------
;; HELPER INSTRUCTIONS for saving the prologue and epilog registers
;; ----------------------------------------------------------------------
;; This pattern will match a stack adjust RTX followed by any number of push
;; RTXs. These RTXs will then be turned into a suitable call to a worker
;; function.
(define_insn ""
[(match_parallel 0 "pattern_is_ok_for_prologue"
[(set (reg:SI 3)
(plus:SI (reg:SI 3) (match_operand:SI 1 "immediate_operand" "i")))
(set (mem:SI (plus:SI (reg:SI 3)
(match_operand:SI 2 "immediate_operand" "i")))
(match_operand:SI 3 "register_is_ok_for_epilogue" "r"))])]
"TARGET_PROLOG_FUNCTION"
"* return construct_save_jarl (operands[0]);
"
[(set_attr "length" "4")
(set_attr "cc" "clobber")])
;; Initialize an interrupt function. Do not depend on TARGET_PROLOG_FUNCTION.
(define_insn "save_interrupt"
[(set (reg:SI 3) (plus:SI (reg:SI 3) (const_int -16)))
(set (mem:SI (reg:SI 3)) (reg:SI 30))
(set (mem:SI (plus:SI (reg:SI 3) (const_int -4))) (reg:SI 10))
(set (mem:SI (plus:SI (reg:SI 3) (const_int -8))) (reg:SI 4))
(set (mem:SI (plus:SI (reg:SI 3) (const_int -12))) (reg:SI 1))]
""
"add -16,sp\;st.w r10,12[sp]\;jarl __save_interrupt,r10"
[(set_attr "length" "12")
(set_attr "cc" "clobber")])
;; Save all registers except for the registers saved in save_interrupt when
;; an interrupt function makes a call.
;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
;; all of memory. This blocks insns from being moved across this point.
;; This is needed because the rest of the compiler is not ready to handle
;; insns this complicated.
(define_insn "save_all_interrupt"
[(unspec_volatile [(const_int 0)] 0)]
""
"jarl __save_all_interrupt,r10"
[(set_attr "length" "4")
(set_attr "cc" "clobber")])
;; This pattern will match a return RTX followed by any number of pop RTXs
;; and possible a stack adjustment as well. These RTXs will be turned into
;; a suitable call to a worker function.
(define_insn ""
[(match_parallel 0 "pattern_is_ok_for_epilogue"
[(return)
(set (reg:SI 3)
(plus:SI (reg:SI 3) (match_operand:SI 1 "immediate_operand" "i")))
(set (match_operand:SI 2 "register_is_ok_for_epilogue" "r")
(mem:SI (plus:SI (reg:SI 3)
(match_operand:SI 3 "immediate_operand" "i"))))])]
"TARGET_PROLOG_FUNCTION && TARGET_V850"
"* return construct_restore_jr (operands[0]);
"
[(set_attr "length" "4")
(set_attr "cc" "clobber")])
;; Restore r1, r4, r10, and return from the interrupt
(define_insn "restore_interrupt"
[(return)
(set (reg:SI 3) (plus:SI (reg:SI 3) (const_int 16)))
(set (reg:SI 30) (mem:SI (plus:SI (reg:SI 3) (const_int 12))))
(set (reg:SI 10) (mem:SI (plus:SI (reg:SI 3) (const_int 8))))
(set (reg:SI 4) (mem:SI (plus:SI (reg:SI 3) (const_int 4))))
(set (reg:SI 1) (mem:SI (reg:SI 3)))]
""
"jr __return_interrupt"
[(set_attr "length" "4")
(set_attr "cc" "clobber")])
;; Restore all registers saved when an interrupt function makes a call.
;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
;; all of memory. This blocks insns from being moved across this point.
;; This is needed because the rest of the compiler is not ready to handle
;; insns this complicated.
(define_insn "restore_all_interrupt"
[(unspec_volatile [(const_int 0)] 1)]
""
"jarl __restore_all_interrupt,r10"
[(set_attr "length" "4")
(set_attr "cc" "clobber")])
;; Save r6-r9 for a variable argument function
(define_insn "save_r6_r9"
[(set (mem:SI (reg:SI 3)) (reg:SI 6))
(set (mem:SI (plus:SI (reg:SI 3) (const_int 4))) (reg:SI 7))
(set (mem:SI (plus:SI (reg:SI 3) (const_int 8))) (reg:SI 8))
(set (mem:SI (plus:SI (reg:SI 3) (const_int 12))) (reg:SI 9))
(clobber (reg:SI 10))]
"TARGET_PROLOG_FUNCTION"
"jarl __save_r6_r9,r10"
[(set_attr "length" "4")
(set_attr "cc" "clobber")])