36 KiB
;; 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" "=d,*a,d,*a,d,*a,d,a,d,m") (match_operand:QI 1 "general_operand" "0,0,I,I,a,d,di,ia,m,d"))] "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" "=d,*a,d,*a,d,*a,d,a,d,m") (match_operand:HI 1 "general_operand" "0,0,I,I,a,d,di,ia,m,d"))] "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" "=d,a,d,a,dm,dm,am,am,d,d,a,a,aR,x") (match_operand:SI 1 "general_operand" "0,0,I,I,d,a,d,a,dim,aim,dim,aim,x,aR"))] "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" "=d,a,d,a,dam,da") (match_operand:SF 1 "general_operand" "0,0,G,G,da,daim"))] "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" "=d,a,d,a,dm,dm,am,am,d,d,a,a") (match_operand:DI 1 "general_operand" "0,0,I,I,d,a,d,a,dim,aim,dim,aim"))] "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" "=d,a,d,a,dm,dm,am,am,d,d,a,a") (match_operand:DF 1 "general_operand" "0,0,G,G,d,a,d,a,dim,aim,dim,aim"))] "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" "da"))] "" "* return output_tst (operands[0], insn);" [(set_attr "cc" "set_znv")])
(define_insn "" [(set (cc0) (zero_extend:SI (match_operand:QI 0 "memory_operand" "d")))] "" "* return output_tst (operands[0], insn);" [(set_attr "cc" "set_znv")])
(define_insn "" [(set (cc0) (zero_extend:SI (match_operand:HI 0 "memory_operand" "d")))] "" "* return output_tst (operands[0], insn);" [(set_attr "cc" "set_znv")])
(define_insn "cmpsi" [(set (cc0) (compare (match_operand:SI 0 "register_operand" "!da,da") (match_operand:SI 1 "nonmemory_operand" "!*0,dai")))] "" "@ 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" "=d,a,a,da,x,&!da") (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,da") (match_operand:SI 2 "nonmemory_operand" "J,J,L,dai,i,da")))] "" "@ inc %0 inc %0 inc4 %0 add %2,%0 add %2,%0 mov %2,%0;add %1,%0" [(set_attr "cc" "set_zn,none_0hit,none_0hit,set_zn,none_0hit,set_zn")])
;; ---------------------------------------------------------------------- ;; SUBTRACT INSTRUCTIONS ;; ----------------------------------------------------------------------
(define_insn "subsi3" [(set (match_operand:SI 0 "register_operand" "=da") (minus:SI (match_operand:SI 1 "register_operand" "0") (match_operand:SI 2 "nonmemory_operand" "dai")))] "" "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" "=d") (mult:SI (match_operand:SI 1 "register_operand" "%0") (match_operand:SI 2 "register_operand" "d")))] "" "* { 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" "=d") (udiv:SI (match_operand:SI 1 "general_operand" "0") (match_operand:SI 2 "general_operand" "d"))) (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" "=d") (div:SI (match_operand:SI 1 "general_operand" "0") (match_operand:SI 2 "general_operand" "d"))) (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" "=d,d") (and:SI (match_operand:SI 1 "register_operand" "%0,0") (match_operand:SI 2 "nonmemory_operand" "N,di")))] "" "* { 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,%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" "=d") (ior:SI (match_operand:SI 1 "register_operand" "%0") (match_operand:SI 2 "nonmemory_operand" "di")))] "" "or %2,%0" [(set_attr "cc" "set_znv")])
;; ---------------------------------------------------------------------- ;; XOR INSTRUCTIONS ;; ----------------------------------------------------------------------
(define_insn "xorsi3" [(set (match_operand:SI 0 "register_operand" "=d") (xor:SI (match_operand:SI 1 "register_operand" "%0") (match_operand:SI 2 "nonmemory_operand" "di")))] "" "xor %2,%0" [(set_attr "cc" "set_znv")])
;; ---------------------------------------------------------------------- ;; NOT INSTRUCTIONS ;; ----------------------------------------------------------------------
(define_insn "one_cmplsi2" [(set (match_operand:SI 0 "register_operand" "=d") (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" "d") (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,d") (match_operand 1 "const_int_operand" "") (match_operand 2 "const_int_operand" "")))] "INTVAL (operands[1]) <= 8 && INTVAL (operands[2]) <= 7" "* { 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); 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" "d") (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,d") 0) (match_operand:SI 1 "const_int_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 "" "=da") (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" "=d,d,d") (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" "=d,d,d") (zero_extend:SI (match_operand:HI 1 "general_operand" "0,d,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" "=d,d") (sign_extend:SI (match_operand:QI 1 "general_operand" "0,d")))] "" "@ extb %0 mov %1,%0;extb %0" [(set_attr "cc" "none_0hit")])
(define_insn "extendhisi2" [(set (match_operand:SI 0 "general_operand" "=d,d") (sign_extend:SI (match_operand:HI 1 "general_operand" "0,d")))] "" "@ exth %0 mov %1,%0;exth %0" [(set_attr "cc" "none_0hit")]) ;; ---------------------------------------------------------------------- ;; SHIFTS ;; ----------------------------------------------------------------------
(define_insn "ashlsi3" [(set (match_operand:SI 0 "register_operand" "=da,d,d,d,d") (ashift:SI (match_operand:SI 1 "register_operand" "0,0,0,0,0") (match_operand:QI 2 "nonmemory_operand" "J,K,M,L,di")))] "" "@ 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" "=d") (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") (match_operand:QI 2 "nonmemory_operand" "di")))] "" "lsr %S2,%0" [(set_attr "cc" "set_zn")])
(define_insn "ashrsi3" [(set (match_operand:SI 0 "register_operand" "=d") (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") (match_operand:QI 2 "nonmemory_operand" "di")))] "" "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)] "" "ret [d2,d3,a2,a3],%0" [(set_attr "cc" "clobber")])
(define_insn "store_movm" [(const_int 1)] "" "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" "=dax") (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" "d")) (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" "d")) (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" "d")) (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" "d")) (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")])