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

1470 lines
38 KiB
Markdown
Raw Normal View History

1998-08-16 21:35:45 +04:00
;; GCC machine description for Matsushita MN10300
;; 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.
;; 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.
1998-08-16 21:35:45 +04:00
;; set_znv - insn sets z,n,v to usable values; c is unusable.
;; set_zn - insn sets z,n to usable values; v,c are unusable.
;; compare - compare instruction
;; invert -- like compare, but flags are inverted.
;; clobber - value of cc is unknown
(define_attr "cc" "none,none_0hit,set_znv,set_zn,compare,clobber,invert"
(const_string "clobber"))
;; ----------------------------------------------------------------------
;; 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 */
if (!register_operand (operand0, QImode)
&& !register_operand (operand1, QImode))
operands[1] = copy_to_mode_reg (QImode, operand1);
}")
(define_insn ""
1998-08-16 21:35:45 +04:00
[(set (match_operand:QI 0 "general_operand" "=dx,*a,dx,*a,dx,*a,dx,*a,dx,m")
(match_operand:QI 1 "general_operand" "0,0,I,I,a,dx,dxi,ia,m,dx"))]
"register_operand (operands[0], QImode)
|| register_operand (operands[1], QImode)"
"*
{
switch (which_alternative)
{
case 0:
case 1:
return \"nop\";
case 2:
return \"clr %0\";
case 3:
if (zero_areg)
{
rtx xoperands[2];
xoperands[0] = operands[0];
xoperands[1] = zero_areg;
if (rtx_equal_p (xoperands[0], xoperands[1]))
output_asm_insn (\"sub %1,%0\", xoperands);
else
output_asm_insn (\"mov %1,%0\", xoperands);
return \"\";
}
/* FALLTHROUGH */
case 4:
case 5:
case 6:
case 7:
return \"mov %1,%0\";
case 8:
case 9:
return \"movbu %1,%0\";
}
}"
[(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
;; 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 */
if (!register_operand (operand1, HImode)
&& !register_operand (operand0, HImode))
operands[1] = copy_to_mode_reg (HImode, operand1);
}")
(define_insn ""
1998-08-16 21:35:45 +04:00
[(set (match_operand:HI 0 "general_operand" "=dx,*a,dx,*a,dx,*a,dx,*a,dx,m")
(match_operand:HI 1 "general_operand" "0,0,I,I,a,dx,dxi,ia,m,dx"))]
"register_operand (operands[0], HImode)
|| register_operand (operands[1], HImode)"
"*
{
switch (which_alternative)
{
case 0:
case 1:
return \"nop\";
case 2:
return \"clr %0\";
case 3:
if (zero_areg)
{
rtx xoperands[2];
xoperands[0] = operands[0];
xoperands[1] = zero_areg;
if (rtx_equal_p (xoperands[0], xoperands[1]))
output_asm_insn (\"sub %1,%0\", xoperands);
else
output_asm_insn (\"mov %1,%0\", xoperands);
return \"\";
}
/* FALLTHROUGH */
case 4:
case 5:
case 6:
case 7:
return \"mov %1,%0\";
case 8:
case 9:
return \"movhu %1,%0\";
}
}"
[(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
;; movsi and helpers
;; We use this to handle addition of two values when one operand is the
;; stack pointer and the other is a memory reference of some kind. Reload
;; does not handle them correctly without this expander.
(define_expand "reload_insi"
[(set (match_operand:SI 0 "register_operand" "=a")
(match_operand:SI 1 "impossible_plus_operand" ""))
(clobber (match_operand:SI 2 "register_operand" "=&r"))]
""
"
{
if (XEXP (operands[1], 0) == stack_pointer_rtx)
{
emit_move_insn (operands[0], XEXP (operands[1], 0));
if (GET_CODE (XEXP (operands[1], 1)) == SUBREG
&& (GET_MODE_SIZE (GET_MODE (XEXP (operands[1], 1)))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (operands[1], 1))))))
emit_move_insn (operands[2],
gen_rtx (ZERO_EXTEND, GET_MODE (XEXP (operands[1], 1)),
SUBREG_REG (XEXP (operands[1], 1))));
else
emit_move_insn (operands[2], XEXP (operands[1], 1));
}
else
{
emit_move_insn (operands[0], XEXP (operands[1], 1));
if (GET_CODE (XEXP (operands[1], 0)) == SUBREG
&& (GET_MODE_SIZE (GET_MODE (XEXP (operands[1], 0)))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (operands[1], 0))))))
emit_move_insn (operands[2],
gen_rtx (ZERO_EXTEND, GET_MODE (XEXP (operands[1], 0)),
SUBREG_REG (XEXP (operands[1], 0))));
else
emit_move_insn (operands[2], XEXP (operands[1], 0));
}
emit_insn (gen_addsi3 (operands[0], operands[0], operands[2]));
DONE;
}")
(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 */
if (!register_operand (operand1, SImode)
&& !register_operand (operand0, SImode))
operands[1] = copy_to_mode_reg (SImode, operand1);
}")
(define_insn ""
[(set (match_operand:SI 0 "general_operand"
1998-08-16 21:35:45 +04:00
"=dx,ax,dx,ax,dxm,dxm,axm,axm,dx,dx,ax,ax,axR,y")
(match_operand:SI 1 "general_operand"
1998-08-16 21:35:45 +04:00
"0,0,I,I,dx,ax,dx,ax,dixm,aixm,dixm,aixm,xy,axR"))]
"register_operand (operands[0], SImode)
|| register_operand (operands[1], SImode)"
"*
{
switch (which_alternative)
{
case 0:
case 1:
return \"nop\";
case 2:
return \"clr %0\";
case 3:
if (zero_areg)
{
rtx xoperands[2];
xoperands[0] = operands[0];
xoperands[1] = zero_areg;
if (rtx_equal_p (xoperands[0], xoperands[1]))
output_asm_insn (\"sub %1,%0\", xoperands);
else
output_asm_insn (\"mov %1,%0\", xoperands);
return \"\";
}
/* FALLTHROUGH */
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
return \"mov %1,%0\";
}
}"
[(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
(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 */
if (!register_operand (operand1, SFmode)
&& !register_operand (operand0, SFmode))
operands[1] = copy_to_mode_reg (SFmode, operand1);
}")
(define_insn ""
1998-08-16 21:35:45 +04:00
[(set (match_operand:SF 0 "general_operand" "=dx,ax,dx,ax,daxm,dax")
(match_operand:SF 1 "general_operand" "0,0,G,G,dax,daxim"))]
"register_operand (operands[0], SFmode)
|| register_operand (operands[1], SFmode)"
"*
{
switch (which_alternative)
{
case 0:
case 1:
return \"nop\";
case 2:
return \"clr %0\";
case 3:
if (zero_areg)
{
rtx xoperands[2];
xoperands[0] = operands[0];
xoperands[1] = zero_areg;
if (rtx_equal_p (xoperands[0], xoperands[1]))
output_asm_insn (\"sub %1,%0\", xoperands);
else
output_asm_insn (\"mov %1,%0\", xoperands);
return \"\";
}
/* FALLTHROUGH */
case 4:
case 5:
return \"mov %1,%0\";
}
}"
[(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit")])
(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 */
if (!register_operand (operand1, DImode)
&& !register_operand (operand0, DImode))
operands[1] = copy_to_mode_reg (DImode, operand1);
}")
(define_insn ""
[(set (match_operand:DI 0 "general_operand"
1998-08-16 21:35:45 +04:00
"=dx,ax,dx,ax,dxm,dxm,axm,axm,dx,dx,ax,ax")
(match_operand:DI 1 "general_operand"
1998-08-16 21:35:45 +04:00
"0,0,I,I,dx,ax,dx,ax,dxim,axim,dxim,axim"))]
"register_operand (operands[0], DImode)
|| register_operand (operands[1], DImode)"
"*
{
long val[2];
REAL_VALUE_TYPE rv;
switch (which_alternative)
{
case 0:
case 1:
return \"nop\";
case 2:
return \"clr %L0\;clr %H0\";
case 3:
{
rtx xoperands[2];
xoperands[0] = operands[0];
xoperands[1] = zero_areg ? zero_areg : operands[1];
if (rtx_equal_p (xoperands[0], xoperands[1]))
output_asm_insn (\"sub %L1,%L0\;mov %L0,%H0\", xoperands);
else
output_asm_insn (\"mov %1,%L0\;mov %L0,%H0\", xoperands);
return \"\";
}
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
if (GET_CODE (operands[1]) == CONST_INT)
{
val[0] = INTVAL (operands[1]);
val[1] = val[0] < 0 ? -1 : 0;
}
if (GET_CODE (operands[1]) == CONST_DOUBLE)
{
if (GET_MODE (operands[1]) == DFmode)
{
REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
}
else if (GET_MODE (operands[1]) == VOIDmode
|| GET_MODE (operands[1]) == DImode)
{
val[0] = CONST_DOUBLE_LOW (operands[1]);
val[1] = CONST_DOUBLE_HIGH (operands[1]);
}
}
if (GET_CODE (operands[1]) == MEM
&& reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0)))
{
rtx temp = operands[0];
while (GET_CODE (temp) == SUBREG)
temp = SUBREG_REG (temp);
if (GET_CODE (temp) != REG)
abort ();
if (reg_overlap_mentioned_p (gen_rtx (REG, SImode, REGNO (temp)),
XEXP (operands[1], 0)))
return \"mov %H1,%H0\;mov %L1,%L0\";
else
return \"mov %L1,%L0\;mov %H1,%H0\";
}
else if (GET_CODE (operands[1]) == MEM
&& CONSTANT_ADDRESS_P (XEXP (operands[1], 0))
&& REGNO_REG_CLASS (REGNO (operands[0])) == ADDRESS_REGS)
{
rtx xoperands[2];
xoperands[0] = operands[0];
xoperands[1] = XEXP (operands[1], 0);
output_asm_insn (\"mov %1,%L0\;mov (4,%L0),%H0\;mov (%L0),%L0\",
xoperands);
return \"\";
}
else
{
if ((GET_CODE (operands[1]) == CONST_INT
|| GET_CODE (operands[1]) == CONST_DOUBLE)
&& val[0] == 0)
{
if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
output_asm_insn (\"clr %L0\", operands);
else if (zero_areg)
{
rtx xoperands[2];
xoperands[0] = operands[0];
xoperands[1] = zero_areg;
if (rtx_equal_p (xoperands[0], xoperands[1]))
output_asm_insn (\"sub %L0,%L0\", xoperands);
else
output_asm_insn (\"mov %1,%L0\", xoperands);
}
else
output_asm_insn (\"mov %L1,%L0\", operands);
}
else
output_asm_insn (\"mov %L1,%L0\", operands);
if ((GET_CODE (operands[1]) == CONST_INT
|| GET_CODE (operands[1]) == CONST_DOUBLE)
&& val[1] == 0)
{
if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
output_asm_insn (\"clr %H0\", operands);
else if (zero_areg)
{
rtx xoperands[2];
xoperands[0] = operands[0];
xoperands[1] = zero_areg;
if (rtx_equal_p (xoperands[0], xoperands[1]))
output_asm_insn (\"sub %H0,%H0\", xoperands);
else
output_asm_insn (\"mov %1,%H0\", xoperands);
}
else
output_asm_insn (\"mov %H1,%H0\", operands);
}
else if ((GET_CODE (operands[1]) == CONST_INT
|| GET_CODE (operands[1]) == CONST_DOUBLE)
&& val[0] == val[1])
output_asm_insn (\"mov %L0,%H0\", operands);
else
output_asm_insn (\"mov %H1,%H0\", operands);
return \"\";
}
}
}"
[(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
(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 */
if (!register_operand (operand1, DFmode)
&& !register_operand (operand0, DFmode))
operands[1] = copy_to_mode_reg (DFmode, operand1);
}")
(define_insn ""
[(set (match_operand:DF 0 "general_operand"
1998-08-16 21:35:45 +04:00
"=dx,ax,dx,ax,dxm,dxm,axm,axm,dx,dx,ax,ax")
(match_operand:DF 1 "general_operand"
1998-08-16 21:35:45 +04:00
"0,0,G,G,dx,ax,dx,ax,dxim,axim,dxim,axim"))]
"register_operand (operands[0], DFmode)
|| register_operand (operands[1], DFmode)"
"*
{
long val[2];
REAL_VALUE_TYPE rv;
switch (which_alternative)
{
case 0:
case 1:
return \"nop\";
case 2:
return \"clr %L0\;clr %H0\";
case 3:
{
rtx xoperands[2];
xoperands[0] = operands[0];
xoperands[1] = zero_areg ? zero_areg : operands[1];
if (rtx_equal_p (xoperands[0], xoperands[1]))
output_asm_insn (\"sub %L1,%L0\;mov %L0,%H0\", xoperands);
else
output_asm_insn (\"mov %1,%L0\;mov %L0,%H0\", xoperands);
return \"\";
}
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
if (GET_CODE (operands[1]) == CONST_INT)
{
val[0] = INTVAL (operands[1]);
val[1] = val[0] < 0 ? -1 : 0;
}
if (GET_CODE (operands[1]) == CONST_DOUBLE)
{
if (GET_MODE (operands[1]) == DFmode)
{
REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
}
else if (GET_MODE (operands[1]) == VOIDmode
|| GET_MODE (operands[1]) == DImode)
{
val[0] = CONST_DOUBLE_LOW (operands[1]);
val[1] = CONST_DOUBLE_HIGH (operands[1]);
}
}
if (GET_CODE (operands[1]) == MEM
&& reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0)))
{
rtx temp = operands[0];
while (GET_CODE (temp) == SUBREG)
temp = SUBREG_REG (temp);
if (GET_CODE (temp) != REG)
abort ();
if (reg_overlap_mentioned_p (gen_rtx (REG, SImode, REGNO (temp)),
XEXP (operands[1], 0)))
return \"mov %H1,%H0\;mov %L1,%L0\";
else
return \"mov %L1,%L0\;mov %H1,%H0\";
}
else if (GET_CODE (operands[1]) == MEM
&& CONSTANT_ADDRESS_P (XEXP (operands[1], 0))
&& REGNO_REG_CLASS (REGNO (operands[0])) == ADDRESS_REGS)
{
rtx xoperands[2];
xoperands[0] = operands[0];
xoperands[1] = XEXP (operands[1], 0);
output_asm_insn (\"mov %1,%L0\;mov (4,%L0),%H0\;mov (%L0),%L0\",
xoperands);
return \"\";
}
else
{
if ((GET_CODE (operands[1]) == CONST_INT
|| GET_CODE (operands[1]) == CONST_DOUBLE)
&& val[0] == 0)
{
if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
output_asm_insn (\"clr %L0\", operands);
else if (zero_areg)
{
rtx xoperands[2];
xoperands[0] = operands[0];
xoperands[1] = zero_areg;
if (rtx_equal_p (xoperands[0], xoperands[1]))
output_asm_insn (\"sub %L0,%L0\", xoperands);
else
output_asm_insn (\"mov %1,%L0\", xoperands);
}
else
output_asm_insn (\"mov %L1,%L0\", operands);
}
else
output_asm_insn (\"mov %L1,%L0\", operands);
if ((GET_CODE (operands[1]) == CONST_INT
|| GET_CODE (operands[1]) == CONST_DOUBLE)
&& val[1] == 0)
{
if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
output_asm_insn (\"clr %H0\", operands);
else if (zero_areg)
{
rtx xoperands[2];
xoperands[0] = operands[0];
xoperands[1] = zero_areg;
if (rtx_equal_p (xoperands[0], xoperands[1]))
output_asm_insn (\"sub %H0,%H0\", xoperands);
else
output_asm_insn (\"mov %1,%H0\", xoperands);
}
else
output_asm_insn (\"mov %H1,%H0\", operands);
}
else if ((GET_CODE (operands[1]) == CONST_INT
|| GET_CODE (operands[1]) == CONST_DOUBLE)
&& val[0] == val[1])
output_asm_insn (\"mov %L0,%H0\", operands);
else
output_asm_insn (\"mov %H1,%H0\", operands);
return \"\";
}
}
}"
[(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
;; ----------------------------------------------------------------------
;; TEST INSTRUCTIONS
;; ----------------------------------------------------------------------
;; Go ahead and define tstsi so we can eliminate redundant tst insns
;; when we start trying to optimize this port.
(define_insn "tstsi"
1998-08-16 21:35:45 +04:00
[(set (cc0) (match_operand:SI 0 "register_operand" "dax"))]
""
"* return output_tst (operands[0], insn);"
[(set_attr "cc" "set_znv")])
(define_insn ""
1998-08-16 21:35:45 +04:00
[(set (cc0) (zero_extend:SI (match_operand:QI 0 "memory_operand" "dx")))]
""
"* return output_tst (operands[0], insn);"
[(set_attr "cc" "set_znv")])
(define_insn ""
1998-08-16 21:35:45 +04:00
[(set (cc0) (zero_extend:SI (match_operand:HI 0 "memory_operand" "dx")))]
""
"* return output_tst (operands[0], insn);"
[(set_attr "cc" "set_znv")])
(define_insn "cmpsi"
[(set (cc0)
1998-08-16 21:35:45 +04:00
(compare (match_operand:SI 0 "register_operand" "!*d*a*x,dax")
(match_operand:SI 1 "nonmemory_operand" "!*0,daxi")))]
""
"@
add 0,%0
cmp %1,%0"
[(set_attr "cc" "invert,compare")])
;; ----------------------------------------------------------------------
;; ADD INSTRUCTIONS
;; ----------------------------------------------------------------------
(define_expand "addsi3"
[(set (match_operand:SI 0 "register_operand" "")
(plus:SI (match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "nonmemory_operand" "")))]
""
"
{
/* We can't add a variable amount directly to the stack pointer;
so do so via a temporary register. */
if (operands[0] == stack_pointer_rtx
&& GET_CODE (operands[1]) != CONST_INT
&& GET_CODE (operands[2]) != CONST_INT)
{
rtx temp = gen_reg_rtx (SImode);
emit_move_insn (temp, gen_rtx (PLUS, SImode, operands[1], operands[2]));
emit_move_insn (operands[0], temp);
DONE;
}
}")
(define_insn ""
1998-08-16 21:35:45 +04:00
[(set (match_operand:SI 0 "register_operand" "=dx,ax,ax,dax,xy,!dax")
(plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,dax")
(match_operand:SI 2 "nonmemory_operand" "J,J,L,daxi,i,dax")))]
""
1998-08-16 21:35:45 +04:00
"*
{
switch (which_alternative)
{
case 0:
case 1:
return \"inc %0\";
case 2:
return \"inc4 %0\";
case 3:
case 4:
return \"add %2,%0\";
case 5:
/* I'm not sure if this can happen or not. Might as well be prepared
and generate the best possible code if it does happen. */
if (true_regnum (operands[0]) == true_regnum (operands[1]))
return \"add %2,%0\";
if (true_regnum (operands[0]) == true_regnum (operands[2]))
return \"add %1,%0\";
/* We have to copy one of the sources into the destination, then add
the other source to the destination.
Carefully select which source to copy to the destination; a naive
implementation will waste a byte when the source classes are different
and the destination is an address register. Selecting the lowest
cost register copy will optimize this sequence. */
if (REGNO_REG_CLASS (true_regnum (operands[1]))
== REGNO_REG_CLASS (true_regnum (operands[0])))
return \"mov %1,%0\;add %2,%0\";
return \"mov %2,%0\;add %1,%0\";
}
}"
[(set_attr "cc" "set_zn,none_0hit,none_0hit,set_zn,none_0hit,set_zn")])
;; ----------------------------------------------------------------------
;; SUBTRACT INSTRUCTIONS
;; ----------------------------------------------------------------------
1998-08-16 21:35:45 +04:00
(define_expand "subsi3"
[(set (match_operand:SI 0 "register_operand" "")
(minus:SI (match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "nonmemory_operand" "")))]
""
"")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=dax")
(minus:SI (match_operand:SI 1 "register_operand" "0")
1998-08-16 21:35:45 +04:00
(match_operand:SI 2 "nonmemory_operand" "daxi")))]
""
"sub %2,%0"
[(set_attr "cc" "set_zn")])
(define_expand "negsi2"
[(set (match_operand:SI 0 "register_operand" "")
(neg:SI (match_operand:SI 1 "register_operand" "")))]
""
"
{
rtx target = gen_reg_rtx (SImode);
emit_move_insn (target, GEN_INT (0));
emit_insn (gen_subsi3 (target, target, operands[1]));
emit_move_insn (operands[0], target);
DONE;
}")
;; ----------------------------------------------------------------------
;; MULTIPLY INSTRUCTIONS
;; ----------------------------------------------------------------------
(define_insn "mulsi3"
1998-08-16 21:35:45 +04:00
[(set (match_operand:SI 0 "register_operand" "=dx")
(mult:SI (match_operand:SI 1 "register_operand" "%0")
1998-08-16 21:35:45 +04:00
(match_operand:SI 2 "register_operand" "dx")))]
""
"*
{
if (TARGET_MULT_BUG)
return \"nop\;nop\;mul %2,%0\";
else
return \"mul %2,%0\";
}"
[(set_attr "cc" "set_zn")])
(define_insn "udivmodsi4"
1998-08-16 21:35:45 +04:00
[(set (match_operand:SI 0 "general_operand" "=dx")
(udiv:SI (match_operand:SI 1 "general_operand" "0")
1998-08-16 21:35:45 +04:00
(match_operand:SI 2 "general_operand" "dx")))
(set (match_operand:SI 3 "general_operand" "=&d")
(umod:SI (match_dup 1) (match_dup 2)))]
""
"*
{
if (zero_dreg)
output_asm_insn (\"mov %0,mdr\", &zero_dreg);
else
output_asm_insn (\"sub %3,%3\;mov %3,mdr\", operands);
if (find_reg_note (insn, REG_UNUSED, operands[3]))
return \"divu %2,%0\";
else
return \"divu %2,%0\;mov mdr,%3\";
}"
[(set_attr "cc" "set_zn")])
(define_insn "divmodsi4"
1998-08-16 21:35:45 +04:00
[(set (match_operand:SI 0 "general_operand" "=dx")
(div:SI (match_operand:SI 1 "general_operand" "0")
1998-08-16 21:35:45 +04:00
(match_operand:SI 2 "general_operand" "dx")))
(set (match_operand:SI 3 "general_operand" "=d")
(mod:SI (match_dup 1) (match_dup 2)))]
""
"*
{
if (find_reg_note (insn, REG_UNUSED, operands[3]))
return \"ext %0\;div %2,%0\";
else
return \"ext %0\;div %2,%0\;mov mdr,%3\";
}"
[(set_attr "cc" "set_zn")])
;; ----------------------------------------------------------------------
;; AND INSTRUCTIONS
;; ----------------------------------------------------------------------
(define_insn "andsi3"
1998-08-16 21:35:45 +04:00
[(set (match_operand:SI 0 "register_operand" "=dx,dx")
(and:SI (match_operand:SI 1 "register_operand" "%0,0")
1998-08-16 21:35:45 +04:00
(match_operand:SI 2 "nonmemory_operand" "N,dxi")))]
""
"*
{
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xff)
return \"extbu %0\";
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xffff)
return \"exthu %0\";
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x7fffffff)
return \"add %0,%0\;lsr 1,%0\";
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x3fffffff)
return \"asl2 %0\;lsr 2,%0\";
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x1fffffff)
return \"add %0,%0\;asl2 %0\;lsr 3,%0\";
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x0fffffff)
1998-08-16 21:35:45 +04:00
return \"asl2 %0\;asl2 %0\;lsr 4,%0\";
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffffe)
return \"lsr 1,%0\;add %0,%0\";
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffffc)
return \"lsr 2,%0\;asl2 %0\";
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffff8)
return \"lsr 3,%0\;add %0,%0\;asl2 %0\";
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffff0)
return \"lsr 4,%0\;asl2 %0\;asl2 %0\";
return \"and %2,%0\";
}"
[(set_attr "cc" "none_0hit,set_znv")])
;; ----------------------------------------------------------------------
;; OR INSTRUCTIONS
;; ----------------------------------------------------------------------
(define_insn "iorsi3"
1998-08-16 21:35:45 +04:00
[(set (match_operand:SI 0 "register_operand" "=dx")
(ior:SI (match_operand:SI 1 "register_operand" "%0")
1998-08-16 21:35:45 +04:00
(match_operand:SI 2 "nonmemory_operand" "dxi")))]
""
"or %2,%0"
[(set_attr "cc" "set_znv")])
;; ----------------------------------------------------------------------
;; XOR INSTRUCTIONS
;; ----------------------------------------------------------------------
(define_insn "xorsi3"
1998-08-16 21:35:45 +04:00
[(set (match_operand:SI 0 "register_operand" "=dx")
(xor:SI (match_operand:SI 1 "register_operand" "%0")
1998-08-16 21:35:45 +04:00
(match_operand:SI 2 "nonmemory_operand" "dxi")))]
""
"xor %2,%0"
[(set_attr "cc" "set_znv")])
;; ----------------------------------------------------------------------
;; NOT INSTRUCTIONS
;; ----------------------------------------------------------------------
(define_insn "one_cmplsi2"
1998-08-16 21:35:45 +04:00
[(set (match_operand:SI 0 "register_operand" "=dx")
(not:SI (match_operand:SI 1 "register_operand" "0")))]
""
"not %0"
[(set_attr "cc" "set_znv")])
;; -----------------------------------------------------------------
;; BIT FIELDS
;; -----------------------------------------------------------------
;; These set/clear memory in byte sized chunks.
;;
;; They are no smaller/faster than loading the value into a register
;; and storing the register, but they don't need a scratch register
;; which may allow for better code generation.
(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=R,d") (const_int 0))]
""
"@
bclr 255,%A0
clr %0"
[(set_attr "cc" "clobber")])
(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=R,d") (const_int -1))]
""
"@
bset 255,%A0
mov -1,%0"
[(set_attr "cc" "clobber,none_0hit")])
(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=R,d")
(subreg:QI
(and:SI (subreg:SI (match_dup 0) 0)
(match_operand:SI 1 "const_int_operand" "i,i")) 0))]
""
"@
bclr %N1,%A0
and %1,%0"
[(set_attr "cc" "clobber,set_znv")])
(define_insn ""
[(set (match_operand:QI 0 "general_operand" "=R,d")
(subreg:QI
(ior:SI (subreg:SI (match_dup 0) 0)
(match_operand:SI 1 "const_int_operand" "i,i")) 0))]
""
"@
bset %1,%A0
or %1,%0"
[(set_attr "cc" "clobber,set_znv")])
(define_insn ""
[(set (cc0)
1998-08-16 21:35:45 +04:00
(zero_extract:SI (match_operand:SI 0 "register_operand" "dx")
(match_operand 1 "const_int_operand" "")
(match_operand 2 "const_int_operand" "")))]
""
"*
{
int len = INTVAL (operands[1]);
int bit = INTVAL (operands[2]);
int mask = 0;
rtx xoperands[2];
while (len > 0)
{
mask |= (1 << bit);
bit++;
len--;
}
xoperands[0] = operands[0];
xoperands[1] = GEN_INT (mask);
output_asm_insn (\"btst %1,%0\", xoperands);
return \"\";
}"
[(set_attr "cc" "set_znv")])
(define_insn ""
[(set (cc0)
1998-08-16 21:35:45 +04:00
(zero_extract:SI (match_operand:QI 0 "general_operand" "R,dx")
(match_operand 1 "const_int_operand" "")
(match_operand 2 "const_int_operand" "")))]
"mask_ok_for_mem_btst (INTVAL (operands[1]), INTVAL (operands[2]))"
"*
{
int len = INTVAL (operands[1]);
int bit = INTVAL (operands[2]);
int mask = 0;
rtx xoperands[2];
while (len > 0)
{
mask |= (1 << bit);
bit++;
len--;
}
/* If the source operand is not a reg (ie it is memory), then extract the
bits from mask that we actually want to test. Note that the mask will
never cross a byte boundary. */
if (!REG_P (operands[0]))
{
if (mask & 0xff)
mask = mask & 0xff;
else if (mask & 0xff00)
mask = (mask >> 8) & 0xff;
else if (mask & 0xff0000)
mask = (mask >> 16) & 0xff;
else if (mask & 0xff000000)
mask = (mask >> 24) & 0xff;
}
xoperands[0] = operands[0];
xoperands[1] = GEN_INT (mask);
if (GET_CODE (operands[0]) == REG)
output_asm_insn (\"btst %1,%0\", xoperands);
else
output_asm_insn (\"btst %1,%A0\", xoperands);
return \"\";
}"
[(set_attr "cc" "set_znv")])
(define_insn ""
1998-08-16 21:35:45 +04:00
[(set (cc0) (and:SI (match_operand:SI 0 "register_operand" "dx")
(match_operand:SI 1 "const_int_operand" "")))]
""
"btst %1,%0"
[(set_attr "cc" "set_znv")])
(define_insn ""
[(set (cc0)
(and:SI
1998-08-16 21:35:45 +04:00
(subreg:SI (match_operand:QI 0 "general_operand" "R,dx") 0)
(match_operand:SI 1 "const_8bit_operand" "")))]
""
"@
btst %1,%A0
btst %1,%0"
[(set_attr "cc" "set_znv")])
;; ----------------------------------------------------------------------
;; 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 ""
[(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;
return \"b%b1 %0\";
}"
[(set_attr "cc" "none")])
(define_insn ""
[(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;
return \"b%B1 %0\";
}"
[(set_attr "cc" "none")])
;; Unconditional and other jump instructions.
(define_insn "jump"
[(set (pc)
(label_ref (match_operand 0 "" "")))]
""
"jmp %l0"
[(set_attr "cc" "none")])
(define_insn "indirect_jump"
[(set (pc) (match_operand:SI 0 "register_operand" "a"))]
""
"jmp (%0)"
[(set_attr "cc" "none")])
(define_insn "tablejump"
[(set (pc) (match_operand:SI 0 "register_operand" "a"))
(use (label_ref (match_operand 1 "" "")))]
""
"jmp (%0)"
[(set_attr "cc" "none")])
;; 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)))
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" "aS"))
(match_operand:SI 1 "general_operand" "g"))]
""
"*
{
if (REG_P (operands[0]))
return \"calls %C0\";
else
return \"call %C0,[],0\";
}"
[(set_attr "cc" "clobber")])
;; 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)))
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"
1998-08-16 21:35:45 +04:00
[(set (match_operand 0 "" "=dax")
(call (mem:QI (match_operand:SI 1 "call_address_operand" "aS"))
(match_operand:SI 2 "general_operand" "g")))]
""
"*
{
if (REG_P (operands[1]))
return \"calls %C1\";
else
return \"call %C1,[],0\";
}"
[(set_attr "cc" "clobber")])
(define_expand "untyped_call"
[(parallel [(call (match_operand 0 "" "")
(const_int 0))
(match_operand 1 "" "")
(match_operand 2 "" "")])]
""
"
{
int i;
emit_call_insn (gen_call (operands[0], const0_rtx));
for (i = 0; i < XVECLEN (operands[2], 0); i++)
{
rtx set = XVECEXP (operands[2], 0, i);
emit_move_insn (SET_DEST (set), SET_SRC (set));
}
DONE;
}")
(define_insn "nop"
[(const_int 0)]
""
"nop"
[(set_attr "cc" "none")])
;; ----------------------------------------------------------------------
;; EXTEND INSTRUCTIONS
;; ----------------------------------------------------------------------
(define_insn "zero_extendqisi2"
1998-08-16 21:35:45 +04:00
[(set (match_operand:SI 0 "general_operand" "=dx,dx,dx")
(zero_extend:SI
(match_operand:QI 1 "general_operand" "0,d,m")))]
""
"@
extbu %0
mov %1,%0\;extbu %0
movbu %1,%0"
[(set_attr "cc" "none_0hit")])
(define_insn "zero_extendhisi2"
1998-08-16 21:35:45 +04:00
[(set (match_operand:SI 0 "general_operand" "=dx,dx,dx")
(zero_extend:SI
1998-08-16 21:35:45 +04:00
(match_operand:HI 1 "general_operand" "0,dx,m")))]
""
"@
exthu %0
mov %1,%0\;exthu %0
movhu %1,%0"
[(set_attr "cc" "none_0hit")])
;;- sign extension instructions
(define_insn "extendqisi2"
1998-08-16 21:35:45 +04:00
[(set (match_operand:SI 0 "general_operand" "=dx,dx")
(sign_extend:SI
1998-08-16 21:35:45 +04:00
(match_operand:QI 1 "general_operand" "0,dx")))]
""
"@
extb %0
mov %1,%0\;extb %0"
[(set_attr "cc" "none_0hit")])
(define_insn "extendhisi2"
1998-08-16 21:35:45 +04:00
[(set (match_operand:SI 0 "general_operand" "=dx,dx")
(sign_extend:SI
1998-08-16 21:35:45 +04:00
(match_operand:HI 1 "general_operand" "0,dx")))]
""
"@
exth %0
mov %1,%0\;exth %0"
[(set_attr "cc" "none_0hit")])
;; ----------------------------------------------------------------------
;; SHIFTS
;; ----------------------------------------------------------------------
(define_insn "ashlsi3"
1998-08-16 21:35:45 +04:00
[(set (match_operand:SI 0 "register_operand" "=dax,dx,dx,dx,dx")
(ashift:SI
(match_operand:SI 1 "register_operand" "0,0,0,0,0")
1998-08-16 21:35:45 +04:00
(match_operand:QI 2 "nonmemory_operand" "J,K,M,L,dxi")))]
""
"@
add %0,%0
asl2 %0
asl2 %0\;add %0,%0
asl2 %0\;asl2 %0
asl %S2,%0"
[(set_attr "cc" "set_zn")])
(define_insn "lshrsi3"
1998-08-16 21:35:45 +04:00
[(set (match_operand:SI 0 "register_operand" "=dx")
(lshiftrt:SI
(match_operand:SI 1 "register_operand" "0")
1998-08-16 21:35:45 +04:00
(match_operand:QI 2 "nonmemory_operand" "dxi")))]
""
"lsr %S2,%0"
[(set_attr "cc" "set_zn")])
(define_insn "ashrsi3"
1998-08-16 21:35:45 +04:00
[(set (match_operand:SI 0 "register_operand" "=dx")
(ashiftrt:SI
(match_operand:SI 1 "register_operand" "0")
1998-08-16 21:35:45 +04:00
(match_operand:QI 2 "nonmemory_operand" "dxi")))]
""
"asr %S2,%0"
[(set_attr "cc" "set_zn")])
;; ----------------------------------------------------------------------
;; PROLOGUE/EPILOGUE
;; ----------------------------------------------------------------------
(define_expand "prologue"
[(const_int 0)]
""
"expand_prologue (); DONE;")
(define_expand "epilogue"
[(return)]
""
"
{
expand_epilogue ();
DONE;
}")
(define_insn "return_internal"
[(const_int 2)]
""
"rets"
[(set_attr "cc" "clobber")])
;; This insn restores the callee saved registers and does a return, it
;; can also deallocate stack space.
(define_insn "return_internal_regs"
[(const_int 0)
(match_operand:SI 0 "const_int_operand" "i")
(return)]
""
1998-08-16 21:35:45 +04:00
"*
{
return \"ret [d2,d3,a2,a3],%0\";
}"
[(set_attr "cc" "clobber")])
(define_insn "store_movm"
[(const_int 1)]
""
1998-08-16 21:35:45 +04:00
"*
{
return \"movm [d2,d3,a2,a3],(sp)\";
}"
[(set_attr "cc" "clobber")])
(define_insn "return"
[(return)]
"can_use_return_insn ()"
"*
{
rtx next = next_active_insn (insn);
if (next
&& GET_CODE (next) == JUMP_INSN
&& GET_CODE (PATTERN (next)) == RETURN)
return \"\";
else
return \"rets\";
}"
[(set_attr "cc" "clobber")])
;; Try to combine consecutive updates of the stack pointer (or any
;; other register for that matter).
(define_peephole
1998-08-16 21:35:45 +04:00
[(set (match_operand:SI 0 "register_operand" "=dxay")
(plus:SI (match_dup 0)
(match_operand 1 "const_int_operand" "")))
(set (match_dup 0)
(plus:SI (match_dup 0)
(match_operand 2 "const_int_operand" "")))]
""
"*
{
operands[1] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[1]));
return \"add %1,%0\";
}"
[(set_attr "cc" "clobber")])
;;
;; We had patterns to check eq/ne, but the they don't work because
;; 0x80000000 + 0x80000000 = 0x0 with a carry out.
;;
;; The Z flag and C flag would be set, and we have no way to
;; check for the Z flag set and C flag clear.
;;
;; This will work on the mn10200 because we can check the ZX flag
;; if the comparison is in HImode.
(define_peephole
1998-08-16 21:35:45 +04:00
[(set (cc0) (match_operand:SI 0 "register_operand" "dx"))
(set (pc) (if_then_else (ge (cc0) (const_int 0))
(match_operand 1 "" "")
(pc)))]
"dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])"
"add %0,%0\;bcc %1"
[(set_attr "cc" "clobber")])
(define_peephole
1998-08-16 21:35:45 +04:00
[(set (cc0) (match_operand:SI 0 "register_operand" "dx"))
(set (pc) (if_then_else (lt (cc0) (const_int 0))
(match_operand 1 "" "")
(pc)))]
"dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])"
"add %0,%0\;bcs %1"
[(set_attr "cc" "clobber")])
(define_peephole
1998-08-16 21:35:45 +04:00
[(set (cc0) (match_operand:SI 0 "register_operand" "dx"))
(set (pc) (if_then_else (ge (cc0) (const_int 0))
(pc)
(match_operand 1 "" "")))]
"dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])"
"add %0,%0\;bcs %1"
[(set_attr "cc" "clobber")])
(define_peephole
1998-08-16 21:35:45 +04:00
[(set (cc0) (match_operand:SI 0 "register_operand" "dx"))
(set (pc) (if_then_else (lt (cc0) (const_int 0))
(pc)
(match_operand 1 "" "")))]
"dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])"
"add %0,%0\;bcc %1"
[(set_attr "cc" "clobber")])