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

1470 lines
38 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 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.
;; 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 ""
[(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 ""
[(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"
"=dx,ax,dx,ax,dxm,dxm,axm,axm,dx,dx,ax,ax,axR,y")
(match_operand:SI 1 "general_operand"
"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 ""
[(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"
"=dx,ax,dx,ax,dxm,dxm,axm,axm,dx,dx,ax,ax")
(match_operand:DI 1 "general_operand"
"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"
"=dx,ax,dx,ax,dxm,dxm,axm,axm,dx,dx,ax,ax")
(match_operand:DF 1 "general_operand"
"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"
[(set (cc0) (match_operand:SI 0 "register_operand" "dax"))]
""
"* return output_tst (operands[0], insn);"
[(set_attr "cc" "set_znv")])
(define_insn ""
[(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 ""
[(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)
(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 ""
[(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")))]
""
"*
{
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
;; ----------------------------------------------------------------------
(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")
(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"
[(set (match_operand:SI 0 "register_operand" "=dx")
(mult:SI (match_operand:SI 1 "register_operand" "%0")
(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"
[(set (match_operand:SI 0 "general_operand" "=dx")
(udiv:SI (match_operand:SI 1 "general_operand" "0")
(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"
[(set (match_operand:SI 0 "general_operand" "=dx")
(div:SI (match_operand:SI 1 "general_operand" "0")
(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"
[(set (match_operand:SI 0 "register_operand" "=dx,dx")
(and:SI (match_operand:SI 1 "register_operand" "%0,0")
(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)
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"
[(set (match_operand:SI 0 "register_operand" "=dx")
(ior:SI (match_operand:SI 1 "register_operand" "%0")
(match_operand:SI 2 "nonmemory_operand" "dxi")))]
""
"or %2,%0"
[(set_attr "cc" "set_znv")])
;; ----------------------------------------------------------------------
;; XOR INSTRUCTIONS
;; ----------------------------------------------------------------------
(define_insn "xorsi3"
[(set (match_operand:SI 0 "register_operand" "=dx")
(xor:SI (match_operand:SI 1 "register_operand" "%0")
(match_operand:SI 2 "nonmemory_operand" "dxi")))]
""
"xor %2,%0"
[(set_attr "cc" "set_znv")])
;; ----------------------------------------------------------------------
;; NOT INSTRUCTIONS
;; ----------------------------------------------------------------------
(define_insn "one_cmplsi2"
[(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)
(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)
(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 ""
[(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
(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"
[(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"
[(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"
[(set (match_operand:SI 0 "general_operand" "=dx,dx,dx")
(zero_extend:SI
(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"
[(set (match_operand:SI 0 "general_operand" "=dx,dx")
(sign_extend:SI
(match_operand:QI 1 "general_operand" "0,dx")))]
""
"@
extb %0
mov %1,%0\;extb %0"
[(set_attr "cc" "none_0hit")])
(define_insn "extendhisi2"
[(set (match_operand:SI 0 "general_operand" "=dx,dx")
(sign_extend:SI
(match_operand:HI 1 "general_operand" "0,dx")))]
""
"@
exth %0
mov %1,%0\;exth %0"
[(set_attr "cc" "none_0hit")])
;; ----------------------------------------------------------------------
;; SHIFTS
;; ----------------------------------------------------------------------
(define_insn "ashlsi3"
[(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")
(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"
[(set (match_operand:SI 0 "register_operand" "=dx")
(lshiftrt:SI
(match_operand:SI 1 "register_operand" "0")
(match_operand:QI 2 "nonmemory_operand" "dxi")))]
""
"lsr %S2,%0"
[(set_attr "cc" "set_zn")])
(define_insn "ashrsi3"
[(set (match_operand:SI 0 "register_operand" "=dx")
(ashiftrt:SI
(match_operand:SI 1 "register_operand" "0")
(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)]
""
"*
{
return \"ret [d2,d3,a2,a3],%0\";
}"
[(set_attr "cc" "clobber")])
(define_insn "store_movm"
[(const_int 1)]
""
"*
{
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
[(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
[(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
[(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
[(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
[(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")])