2628 lines
75 KiB
Markdown
2628 lines
75 KiB
Markdown
|
;; GCC machine description for Matsushita MN10300
|
|||
|
;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
|
|||
|
;; 2007, 2008 Free Software Foundation, Inc.
|
|||
|
;; Contributed by Jeff Law (law@cygnus.com).
|
|||
|
|
|||
|
;; This file is part of GCC.
|
|||
|
|
|||
|
;; GCC 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 3, or (at your option)
|
|||
|
;; any later version.
|
|||
|
|
|||
|
;; GCC 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 GCC; see the file COPYING3. If not see
|
|||
|
;; <http://www.gnu.org/licenses/>.
|
|||
|
|
|||
|
;; 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
|
|||
|
;; clobber - value of cc is unknown
|
|||
|
(define_attr "cc" "none,none_0hit,set_znv,set_zn,compare,clobber"
|
|||
|
(const_string "clobber"))
|
|||
|
|
|||
|
(define_constants [
|
|||
|
(PIC_REG 6)
|
|||
|
(SP_REG 9)
|
|||
|
|
|||
|
(UNSPEC_INT_LABEL 0)
|
|||
|
(UNSPEC_PIC 1)
|
|||
|
(UNSPEC_GOT 2)
|
|||
|
(UNSPEC_GOTOFF 3)
|
|||
|
(UNSPEC_PLT 4)
|
|||
|
(UNSPEC_GOTSYM_OFF 5)
|
|||
|
])
|
|||
|
|
|||
|
(include "predicates.md")
|
|||
|
(include "constraints.md")
|
|||
|
|
|||
|
;; ----------------------------------------------------------------------
|
|||
|
;; 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 "nonimmediate_operand" "=d*x*a*f,d*x,d*x*a,d*x*a,m,*f,d*x*a")
|
|||
|
(match_operand:QI 1 "general_operand" "0,I,d*xai,m,d*xa,d*xa*f,*f"))]
|
|||
|
"TARGET_AM33
|
|||
|
&& (register_operand (operands[0], QImode)
|
|||
|
|| register_operand (operands[1], QImode))"
|
|||
|
"*
|
|||
|
{
|
|||
|
switch (which_alternative)
|
|||
|
{
|
|||
|
case 0:
|
|||
|
return \"nop\";
|
|||
|
case 1:
|
|||
|
return \"clr %0\";
|
|||
|
case 2:
|
|||
|
if (GET_CODE (operands[1]) == CONST_DOUBLE)
|
|||
|
{
|
|||
|
rtx xoperands[2];
|
|||
|
xoperands[0] = operands[0];
|
|||
|
xoperands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
|
|||
|
output_asm_insn (\"mov %1,%0\", xoperands);
|
|||
|
return \"\";
|
|||
|
}
|
|||
|
|
|||
|
if (REGNO_REG_CLASS (true_regnum (operands[0])) == EXTENDED_REGS
|
|||
|
&& GET_CODE (operands[1]) == CONST_INT)
|
|||
|
{
|
|||
|
HOST_WIDE_INT val = INTVAL (operands[1]);
|
|||
|
|
|||
|
if (((val & 0x80) && ! (val & 0xffffff00))
|
|||
|
|| ((val & 0x800000) && ! (val & 0xff000000)))
|
|||
|
return \"movu %1,%0\";
|
|||
|
}
|
|||
|
return \"mov %1,%0\";
|
|||
|
case 3:
|
|||
|
case 4:
|
|||
|
return \"movbu %1,%0\";
|
|||
|
case 5:
|
|||
|
case 6:
|
|||
|
return \"fmov %1,%0\";
|
|||
|
default:
|
|||
|
gcc_unreachable ();
|
|||
|
}
|
|||
|
}"
|
|||
|
[(set_attr "cc" "none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:QI 0 "nonimmediate_operand" "=d*a,d,d,!*a,d*a,d,m")
|
|||
|
(match_operand:QI 1 "general_operand" "0,I,i,i,da,m,d"))]
|
|||
|
"register_operand (operands[0], QImode)
|
|||
|
|| register_operand (operands[1], QImode)"
|
|||
|
"*
|
|||
|
{
|
|||
|
switch (which_alternative)
|
|||
|
{
|
|||
|
case 0:
|
|||
|
return \"nop\";
|
|||
|
case 1:
|
|||
|
return \"clr %0\";
|
|||
|
case 2:
|
|||
|
case 3:
|
|||
|
case 4:
|
|||
|
if (GET_CODE (operands[1]) == CONST_DOUBLE)
|
|||
|
{
|
|||
|
rtx xoperands[2];
|
|||
|
xoperands[0] = operands[0];
|
|||
|
xoperands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
|
|||
|
output_asm_insn (\"mov %1,%0\", xoperands);
|
|||
|
return \"\";
|
|||
|
}
|
|||
|
|
|||
|
return \"mov %1,%0\";
|
|||
|
case 5:
|
|||
|
case 6:
|
|||
|
return \"movbu %1,%0\";
|
|||
|
default:
|
|||
|
gcc_unreachable ();
|
|||
|
}
|
|||
|
}"
|
|||
|
[(set_attr "cc" "none,clobber,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 "nonimmediate_operand" "=d*x*a*f,d*x,d*x*a,d*x*a,m,*f,d*x*a")
|
|||
|
(match_operand:HI 1 "general_operand" "0,I,d*x*ai,m,d*x*a,d*x*a*f,*f"))]
|
|||
|
"TARGET_AM33
|
|||
|
&& (register_operand (operands[0], HImode)
|
|||
|
|| register_operand (operands[1], HImode))"
|
|||
|
"*
|
|||
|
{
|
|||
|
switch (which_alternative)
|
|||
|
{
|
|||
|
case 0:
|
|||
|
return \"nop\";
|
|||
|
case 1:
|
|||
|
return \"clr %0\";
|
|||
|
case 2:
|
|||
|
if (GET_CODE (operands[1]) == CONST_DOUBLE)
|
|||
|
{
|
|||
|
rtx xoperands[2];
|
|||
|
xoperands[0] = operands[0];
|
|||
|
xoperands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
|
|||
|
output_asm_insn (\"mov %1,%0\", xoperands);
|
|||
|
return \"\";
|
|||
|
}
|
|||
|
|
|||
|
if (REGNO_REG_CLASS (true_regnum (operands[0])) == EXTENDED_REGS
|
|||
|
&& GET_CODE (operands[1]) == CONST_INT)
|
|||
|
{
|
|||
|
HOST_WIDE_INT val = INTVAL (operands[1]);
|
|||
|
|
|||
|
if (((val & 0x80) && ! (val & 0xffffff00))
|
|||
|
|| ((val & 0x800000) && ! (val & 0xff000000)))
|
|||
|
return \"movu %1,%0\";
|
|||
|
}
|
|||
|
return \"mov %1,%0\";
|
|||
|
case 3:
|
|||
|
case 4:
|
|||
|
return \"movhu %1,%0\";
|
|||
|
case 5:
|
|||
|
case 6:
|
|||
|
return \"fmov %1,%0\";
|
|||
|
default:
|
|||
|
gcc_unreachable ();
|
|||
|
}
|
|||
|
}"
|
|||
|
[(set_attr "cc" "none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:HI 0 "nonimmediate_operand" "=d*a,d,d,!*a,d*a,d,m")
|
|||
|
(match_operand:HI 1 "general_operand" "0,I,i,i,da,m,d"))]
|
|||
|
"register_operand (operands[0], HImode)
|
|||
|
|| register_operand (operands[1], HImode)"
|
|||
|
"*
|
|||
|
{
|
|||
|
switch (which_alternative)
|
|||
|
{
|
|||
|
case 0:
|
|||
|
return \"nop\";
|
|||
|
case 1:
|
|||
|
return \"clr %0\";
|
|||
|
case 2:
|
|||
|
case 3:
|
|||
|
case 4:
|
|||
|
if (GET_CODE (operands[1]) == CONST_DOUBLE)
|
|||
|
{
|
|||
|
rtx xoperands[2];
|
|||
|
xoperands[0] = operands[0];
|
|||
|
xoperands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
|
|||
|
output_asm_insn (\"mov %1,%0\", xoperands);
|
|||
|
return \"\";
|
|||
|
}
|
|||
|
return \"mov %1,%0\";
|
|||
|
case 5:
|
|||
|
case 6:
|
|||
|
return \"movhu %1,%0\";
|
|||
|
default:
|
|||
|
gcc_unreachable ();
|
|||
|
}
|
|||
|
}"
|
|||
|
[(set_attr "cc" "none,clobber,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)
|
|||
|
{
|
|||
|
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));
|
|||
|
emit_move_insn (operands[0], XEXP (operands[1], 0));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
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_move_insn (operands[0], XEXP (operands[1], 1));
|
|||
|
}
|
|||
|
emit_insn (gen_addsi3 (operands[0], operands[0], operands[2]));
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
(define_insn "pop_pic_reg"
|
|||
|
[(set (reg:SI PIC_REG)
|
|||
|
(mem:SI (post_inc:SI (reg:SI SP_REG))))]
|
|||
|
"reload_completed"
|
|||
|
"movm (sp),[a2]")
|
|||
|
|
|||
|
(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);
|
|||
|
if (flag_pic)
|
|||
|
{
|
|||
|
rtx temp;
|
|||
|
if (SYMBOLIC_CONST_P (operands[1]))
|
|||
|
{
|
|||
|
if (GET_CODE (operands[0]) == MEM)
|
|||
|
operands[1] = force_reg (Pmode, operands[1]);
|
|||
|
else
|
|||
|
{
|
|||
|
temp = (!can_create_pseudo_p ()
|
|||
|
? operands[0]
|
|||
|
: gen_reg_rtx (Pmode));
|
|||
|
operands[1] = legitimize_pic_address (operands[1], temp);
|
|||
|
}
|
|||
|
}
|
|||
|
else if (GET_CODE (operands[1]) == CONST
|
|||
|
&& GET_CODE (XEXP (operands[1], 0)) == PLUS
|
|||
|
&& SYMBOLIC_CONST_P (XEXP (XEXP (operands[1], 0), 0)))
|
|||
|
{
|
|||
|
temp = !can_create_pseudo_p () ? operands[0] : gen_reg_rtx (Pmode);
|
|||
|
temp = legitimize_pic_address (XEXP (XEXP (operands[1], 0), 0),
|
|||
|
temp);
|
|||
|
operands[1] = expand_binop (SImode, add_optab, temp,
|
|||
|
XEXP (XEXP (operands[1], 0), 1),
|
|||
|
(!can_create_pseudo_p ()
|
|||
|
? temp
|
|||
|
: gen_reg_rtx (Pmode)),
|
|||
|
0, OPTAB_LIB_WIDEN);
|
|||
|
}
|
|||
|
}
|
|||
|
}")
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "nonimmediate_operand"
|
|||
|
"=dx,ax,dx,a,dxm,dxm,axm,axm,dx,dx,ax,ax,axR,!*y,*f,*f,dxaQ")
|
|||
|
(match_operand:SI 1 "general_operand"
|
|||
|
"0,0,I,I,dx,ax,dx,ax,dixm,aixm,dixm,aixm,!*y,axR,0,dxaQi*f,*f"))]
|
|||
|
"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:
|
|||
|
case 4:
|
|||
|
case 5:
|
|||
|
case 6:
|
|||
|
case 7:
|
|||
|
case 8:
|
|||
|
case 9:
|
|||
|
case 10:
|
|||
|
case 11:
|
|||
|
case 12:
|
|||
|
case 13:
|
|||
|
if (GET_CODE (operands[1]) == CONST_DOUBLE)
|
|||
|
{
|
|||
|
rtx xoperands[2];
|
|||
|
xoperands[0] = operands[0];
|
|||
|
xoperands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
|
|||
|
output_asm_insn (\"mov %1,%0\", xoperands);
|
|||
|
return \"\";
|
|||
|
}
|
|||
|
|
|||
|
if (REGNO_REG_CLASS (true_regnum (operands[0])) == EXTENDED_REGS
|
|||
|
&& GET_CODE (operands[1]) == CONST_INT)
|
|||
|
{
|
|||
|
HOST_WIDE_INT val = INTVAL (operands[1]);
|
|||
|
|
|||
|
if (((val & 0x80) && ! (val & 0xffffff00))
|
|||
|
|| ((val & 0x800000) && ! (val & 0xff000000)))
|
|||
|
return \"movu %1,%0\";
|
|||
|
}
|
|||
|
return \"mov %1,%0\";
|
|||
|
case 14:
|
|||
|
return \"nop\";
|
|||
|
case 15:
|
|||
|
case 16:
|
|||
|
return \"fmov %1,%0\";
|
|||
|
default:
|
|||
|
gcc_unreachable ();
|
|||
|
}
|
|||
|
}"
|
|||
|
[(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,none,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 "nonimmediate_operand" "=f,dx,ax,dx,a,f,dxaQ,daxm,dax")
|
|||
|
(match_operand:SF 1 "general_operand" "0,0,0,G,G,fdxaQF,f,dax,daxFm"))]
|
|||
|
"register_operand (operands[0], SFmode)
|
|||
|
|| register_operand (operands[1], SFmode)"
|
|||
|
"*
|
|||
|
{
|
|||
|
switch (which_alternative)
|
|||
|
{
|
|||
|
case 0:
|
|||
|
case 1:
|
|||
|
case 2:
|
|||
|
return \"nop\";
|
|||
|
case 3:
|
|||
|
return \"clr %0\";
|
|||
|
/* case 4: below */
|
|||
|
case 5:
|
|||
|
case 6:
|
|||
|
return \"fmov %1, %0\";
|
|||
|
case 4:
|
|||
|
case 7:
|
|||
|
case 8:
|
|||
|
if (REGNO_REG_CLASS (true_regnum (operands[0])) == EXTENDED_REGS
|
|||
|
&& GET_CODE (operands[1]) == CONST_INT)
|
|||
|
{
|
|||
|
HOST_WIDE_INT val = INTVAL (operands[1]);
|
|||
|
|
|||
|
if (((val & 0x80) && ! (val & 0xffffff00))
|
|||
|
|| ((val & 0x800000) && ! (val & 0xff000000)))
|
|||
|
return \"movu %1,%0\";
|
|||
|
}
|
|||
|
return \"mov %1,%0\";
|
|||
|
default:
|
|||
|
gcc_unreachable ();
|
|||
|
}
|
|||
|
}"
|
|||
|
[(set_attr "cc" "none,none,none,clobber,none_0hit,none_0hit,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 "nonimmediate_operand"
|
|||
|
"=dx,ax,dx,a,dxm,dxm,axm,axm,dx,dx,ax,ax,*f,*f,*f,dxa,*f,Q")
|
|||
|
(match_operand:DI 1 "general_operand"
|
|||
|
"0,0,I,I,dx,ax,dx,ax,dxim,axim,dxim,axim,0,*f,dxai,*f,Q,*f"))]
|
|||
|
"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:
|
|||
|
if (rtx_equal_p (operands[0], operands[1]))
|
|||
|
return \"sub %L1,%L0\;mov %L0,%H0\";
|
|||
|
else
|
|||
|
return \"mov %1,%L0\;mov %L0,%H0\";
|
|||
|
case 4:
|
|||
|
case 5:
|
|||
|
case 6:
|
|||
|
case 7:
|
|||
|
case 8:
|
|||
|
case 9:
|
|||
|
case 10:
|
|||
|
case 11:
|
|||
|
if (GET_CODE (operands[1]) == CONST_INT)
|
|||
|
{
|
|||
|
rtx low, high;
|
|||
|
split_double (operands[1], &low, &high);
|
|||
|
val[0] = INTVAL (low);
|
|||
|
val[1] = INTVAL (high);
|
|||
|
}
|
|||
|
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);
|
|||
|
|
|||
|
gcc_assert (GET_CODE (temp) == REG);
|
|||
|
|
|||
|
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
|
|||
|
output_asm_insn (\"mov %L1,%L0\", operands);
|
|||
|
}
|
|||
|
else if ((GET_CODE (operands[1]) == CONST_INT
|
|||
|
|| GET_CODE (operands[1]) == CONST_DOUBLE)
|
|||
|
&& (REGNO_REG_CLASS (true_regnum (operands[0]))
|
|||
|
== EXTENDED_REGS)
|
|||
|
&& (((val[0] & 0x80) && ! (val[0] & 0xffffff00))
|
|||
|
|| ((val[0] & 0x800000) && ! (val[0] & 0xff000000))))
|
|||
|
output_asm_insn (\"movu %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
|
|||
|
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 if ((GET_CODE (operands[1]) == CONST_INT
|
|||
|
|| GET_CODE (operands[1]) == CONST_DOUBLE)
|
|||
|
&& (REGNO_REG_CLASS (true_regnum (operands[0]))
|
|||
|
== EXTENDED_REGS)
|
|||
|
&& (((val[1] & 0x80) && ! (val[1] & 0xffffff00))
|
|||
|
|| ((val[1] & 0x800000) && ! (val[1] & 0xff000000))))
|
|||
|
output_asm_insn (\"movu %H1,%H0\", operands);
|
|||
|
else
|
|||
|
output_asm_insn (\"mov %H1,%H0\", operands);
|
|||
|
return \"\";
|
|||
|
}
|
|||
|
case 12:
|
|||
|
return \"nop\";
|
|||
|
case 13:
|
|||
|
case 14:
|
|||
|
case 15:
|
|||
|
return \"fmov %L1, %L0\;fmov %H1, %H0\";
|
|||
|
case 16:
|
|||
|
if (GET_CODE (operands[1]) == MEM
|
|||
|
&& GET_CODE (XEXP (operands[1], 0)) == CONST_INT
|
|||
|
&& (INTVAL (XEXP (operands[1], 0)) & 7) == 0)
|
|||
|
return \"fmov %D1, %D0\";
|
|||
|
else
|
|||
|
return \"fmov %L1, %L0\;fmov %H1, %H0\";
|
|||
|
case 17:
|
|||
|
if (GET_CODE (operands[0]) == MEM
|
|||
|
&& GET_CODE (XEXP (operands[0], 0)) == CONST_INT
|
|||
|
&& (INTVAL (XEXP (operands[0], 0)) & 7) == 0)
|
|||
|
return \"fmov %D1, %D0\";
|
|||
|
else
|
|||
|
return \"fmov %L1, %L0\;fmov %H1, %H0\";
|
|||
|
default:
|
|||
|
gcc_unreachable ();
|
|||
|
}
|
|||
|
}"
|
|||
|
[(set (attr "cc")
|
|||
|
(cond
|
|||
|
[
|
|||
|
(ior (lt (symbol_ref "which_alternative") (const_int 2))
|
|||
|
(eq (symbol_ref "which_alternative") (const_int 12))
|
|||
|
) (const_string "none")
|
|||
|
(eq (symbol_ref "which_alternative") (const_int 2)
|
|||
|
) (const_string "clobber")
|
|||
|
(eq (symbol_ref "which_alternative") (const_int 3)
|
|||
|
) (if_then_else
|
|||
|
(ne (symbol_ref "rtx_equal_p (operands[0], operands[1])")
|
|||
|
(const_int 0)) (const_string "clobber")
|
|||
|
(const_string "none_0hit"))
|
|||
|
(ior (eq (symbol_ref "which_alternative") (const_int 8))
|
|||
|
(eq (symbol_ref "which_alternative") (const_int 9))
|
|||
|
) (if_then_else
|
|||
|
(ne (symbol_ref "mn10300_wide_const_load_uses_clr
|
|||
|
(operands)")
|
|||
|
(const_int 0)) (const_string "clobber")
|
|||
|
(const_string "none_0hit"))
|
|||
|
] (const_string "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 "nonimmediate_operand"
|
|||
|
"=f,dx,ax,dx,f,f,dxa,f,Q,a,dxm,dxm,axm,axm,dx,dx,ax,ax")
|
|||
|
(match_operand:DF 1 "general_operand"
|
|||
|
"0,0,0,G,f,dxaF,f,Q,f,G,dx,ax,dx,ax,dxFm,axFm,dxFm,axFm"))]
|
|||
|
"register_operand (operands[0], DFmode)
|
|||
|
|| register_operand (operands[1], DFmode)"
|
|||
|
"*
|
|||
|
{
|
|||
|
long val[2];
|
|||
|
REAL_VALUE_TYPE rv;
|
|||
|
|
|||
|
switch (which_alternative)
|
|||
|
{
|
|||
|
case 0:
|
|||
|
case 1:
|
|||
|
case 2:
|
|||
|
return \"nop\";
|
|||
|
|
|||
|
case 3:
|
|||
|
return \"clr %L0\;clr %H0\";
|
|||
|
|
|||
|
case 4:
|
|||
|
case 5:
|
|||
|
case 6:
|
|||
|
return \"fmov %L1, %L0\;fmov %H1, %H0\";
|
|||
|
|
|||
|
case 7:
|
|||
|
if (GET_CODE (operands[1]) == MEM
|
|||
|
&& GET_CODE (XEXP (operands[1], 0)) == CONST_INT
|
|||
|
&& (INTVAL (XEXP (operands[1], 0)) & 7) == 0)
|
|||
|
return \"fmov %D1, %D0\";
|
|||
|
else
|
|||
|
return \"fmov %L1, %L0\;fmov %H1, %H0\";
|
|||
|
|
|||
|
case 8:
|
|||
|
if (GET_CODE (operands[0]) == MEM
|
|||
|
&& GET_CODE (XEXP (operands[0], 0)) == CONST_INT
|
|||
|
&& (INTVAL (XEXP (operands[0], 0)) & 7) == 0)
|
|||
|
return \"fmov %D1, %D0\";
|
|||
|
else
|
|||
|
return \"fmov %L1, %L0\;fmov %H1, %H0\";
|
|||
|
|
|||
|
case 9:
|
|||
|
if (rtx_equal_p (operands[0], operands[1]))
|
|||
|
return \"sub %L1,%L0\;mov %L0,%H0\";
|
|||
|
else
|
|||
|
return \"mov %1,%L0\;mov %L0,%H0\";
|
|||
|
case 10:
|
|||
|
case 11:
|
|||
|
case 12:
|
|||
|
case 13:
|
|||
|
case 14:
|
|||
|
case 15:
|
|||
|
case 16:
|
|||
|
case 17:
|
|||
|
if (GET_CODE (operands[1]) == CONST_INT)
|
|||
|
{
|
|||
|
rtx low, high;
|
|||
|
split_double (operands[1], &low, &high);
|
|||
|
val[0] = INTVAL (low);
|
|||
|
val[1] = INTVAL (high);
|
|||
|
}
|
|||
|
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);
|
|||
|
|
|||
|
gcc_assert (GET_CODE (temp) == REG);
|
|||
|
|
|||
|
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
|
|||
|
output_asm_insn (\"mov %L1,%L0\", operands);
|
|||
|
}
|
|||
|
else if ((GET_CODE (operands[1]) == CONST_INT
|
|||
|
|| GET_CODE (operands[1]) == CONST_DOUBLE)
|
|||
|
&& (REGNO_REG_CLASS (true_regnum (operands[0]))
|
|||
|
== EXTENDED_REGS)
|
|||
|
&& (((val[0] & 0x80) && ! (val[0] & 0xffffff00))
|
|||
|
|| ((val[0] & 0x800000) && ! (val[0] & 0xff000000))))
|
|||
|
output_asm_insn (\"movu %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
|
|||
|
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 if ((GET_CODE (operands[1]) == CONST_INT
|
|||
|
|| GET_CODE (operands[1]) == CONST_DOUBLE)
|
|||
|
&& (REGNO_REG_CLASS (true_regnum (operands[0]))
|
|||
|
== EXTENDED_REGS)
|
|||
|
&& (((val[1] & 0x80) && ! (val[1] & 0xffffff00))
|
|||
|
|| ((val[1] & 0x800000) && ! (val[1] & 0xff000000))))
|
|||
|
output_asm_insn (\"movu %H1,%H0\", operands);
|
|||
|
else
|
|||
|
output_asm_insn (\"mov %H1,%H0\", operands);
|
|||
|
return \"\";
|
|||
|
}
|
|||
|
default:
|
|||
|
gcc_unreachable ();
|
|||
|
}
|
|||
|
}"
|
|||
|
[(set (attr "cc")
|
|||
|
(cond
|
|||
|
[
|
|||
|
(lt (symbol_ref "which_alternative") (const_int 3)
|
|||
|
) (const_string "none")
|
|||
|
(eq (symbol_ref "which_alternative") (const_int 3)
|
|||
|
) (const_string "clobber")
|
|||
|
(eq (symbol_ref "which_alternative") (const_int 9)
|
|||
|
) (if_then_else
|
|||
|
(ne (symbol_ref "rtx_equal_p (operands[0], operands[1])")
|
|||
|
(const_int 0)) (const_string "clobber")
|
|||
|
(const_string "none_0hit"))
|
|||
|
(ior (eq (symbol_ref "which_alternative") (const_int 14))
|
|||
|
(eq (symbol_ref "which_alternative") (const_int 15))
|
|||
|
) (if_then_else
|
|||
|
(ne (symbol_ref "mn10300_wide_const_load_uses_clr
|
|||
|
(operands)")
|
|||
|
(const_int 0)) (const_string "clobber")
|
|||
|
(const_string "none_0hit"))
|
|||
|
] (const_string "none_0hit")))])
|
|||
|
|
|||
|
|
|||
|
|
|||
|
;; ----------------------------------------------------------------------
|
|||
|
;; TEST INSTRUCTIONS
|
|||
|
;; ----------------------------------------------------------------------
|
|||
|
|
|||
|
(define_insn "*tst_extqisi_am33"
|
|||
|
[(set (cc0) (compare
|
|||
|
(zero_extend:SI (match_operand:QI 0 "memory_operand" "dx,!a"))
|
|||
|
(const_int 0)))]
|
|||
|
"TARGET_AM33"
|
|||
|
"* return output_tst (operands[0], insn);"
|
|||
|
[(set_attr "cc" "set_znv")])
|
|||
|
|
|||
|
(define_insn "*tst_extqisi"
|
|||
|
[(set (cc0) (compare
|
|||
|
(zero_extend:SI (match_operand:QI 0 "memory_operand" "dx"))
|
|||
|
(const_int 0)))]
|
|||
|
""
|
|||
|
"* return output_tst (operands[0], insn);"
|
|||
|
[(set_attr "cc" "set_znv")])
|
|||
|
|
|||
|
(define_insn "*tst_exthisi_am33"
|
|||
|
[(set (cc0) (compare
|
|||
|
(zero_extend:SI (match_operand:HI 0 "memory_operand" "dx,!a"))
|
|||
|
(const_int 0)))]
|
|||
|
"TARGET_AM33"
|
|||
|
"* return output_tst (operands[0], insn);"
|
|||
|
[(set_attr "cc" "set_znv")])
|
|||
|
|
|||
|
(define_insn "*tst_exthisi"
|
|||
|
[(set (cc0) (compare
|
|||
|
(zero_extend:SI (match_operand:HI 0 "memory_operand" "dx"))
|
|||
|
(const_int 0)))]
|
|||
|
""
|
|||
|
"* return output_tst (operands[0], insn);"
|
|||
|
[(set_attr "cc" "set_znv")])
|
|||
|
|
|||
|
;; Ordinarily, the cmp instruction will set the Z bit of cc0 to 1 if
|
|||
|
;; its operands hold equal values, but the operands of a cmp
|
|||
|
;; instruction must be distinct registers. In the case where we'd
|
|||
|
;; like to compare a register to itself, we can achieve this effect
|
|||
|
;; with a btst 0,d0 instead. (This will not alter the contents of d0
|
|||
|
;; but will have the proper effect on cc0. Using d0 is arbitrary; any
|
|||
|
;; data register would work.)
|
|||
|
|
|||
|
;; Even though the first alternative would be preferable if it can
|
|||
|
;; possibly match, reload must not be given the opportunity to attempt
|
|||
|
;; to use it. It assumes that such matches can only occur when one of
|
|||
|
;; the operands is used for input and the other for output. Since
|
|||
|
;; this is not the case, it abort()s. Indeed, such a reload cannot be
|
|||
|
;; possibly satisfied, so just mark the alternative with a `!', so
|
|||
|
;; that it is not considered by reload.
|
|||
|
|
|||
|
(define_insn "*cmpsi"
|
|||
|
[(set (cc0)
|
|||
|
(compare (match_operand:SI 0 "register_operand" "!*d*a*x,dax,dax")
|
|||
|
(match_operand:SI 1 "nonmemory_operand" "*0,I,daxi")))]
|
|||
|
""
|
|||
|
"*
|
|||
|
{
|
|||
|
if (which_alternative == 0)
|
|||
|
return \"btst 0,d0\";
|
|||
|
if (which_alternative == 1)
|
|||
|
return output_tst (operands[0], insn);
|
|||
|
return \"cmp %1,%0\";
|
|||
|
}"
|
|||
|
[(set_attr "cc" "compare,set_znv,compare")])
|
|||
|
|
|||
|
(define_insn "*cmpsf"
|
|||
|
[(set (cc0)
|
|||
|
(compare (match_operand:SF 0 "register_operand" "f,f")
|
|||
|
(match_operand:SF 1 "nonmemory_operand" "f,F")))]
|
|||
|
"TARGET_AM33_2"
|
|||
|
"fcmp %1,%0"
|
|||
|
[(set_attr "cc" "compare,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" "")))]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=dx,a,x,a,dax,!*y,!dax")
|
|||
|
(plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,dax")
|
|||
|
(match_operand:SI 2 "nonmemory_operand" "J,J,L,L,daxi,i,dax")))]
|
|||
|
"TARGET_AM33"
|
|||
|
"*
|
|||
|
{
|
|||
|
switch (which_alternative)
|
|||
|
{
|
|||
|
case 0:
|
|||
|
case 1:
|
|||
|
return \"inc %0\";
|
|||
|
case 2:
|
|||
|
case 3:
|
|||
|
return \"inc4 %0\";
|
|||
|
case 4:
|
|||
|
case 5:
|
|||
|
return \"add %2,%0\";
|
|||
|
case 6:
|
|||
|
{
|
|||
|
enum reg_class src1_class, src2_class, dst_class;
|
|||
|
|
|||
|
src1_class = REGNO_REG_CLASS (true_regnum (operands[1]));
|
|||
|
src2_class = REGNO_REG_CLASS (true_regnum (operands[2]));
|
|||
|
dst_class = REGNO_REG_CLASS (true_regnum (operands[0]));
|
|||
|
|
|||
|
/* 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\";
|
|||
|
|
|||
|
/* Catch cases where no extended register was used. These should be
|
|||
|
handled just like the mn10300. */
|
|||
|
if (src1_class != EXTENDED_REGS
|
|||
|
&& src2_class != EXTENDED_REGS
|
|||
|
&& dst_class != EXTENDED_REGS)
|
|||
|
{
|
|||
|
/* 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\";
|
|||
|
}
|
|||
|
|
|||
|
/* At least one register is an extended register. */
|
|||
|
|
|||
|
/* The three operand add instruction on the am33 is a win iff the
|
|||
|
output register is an extended register, or if both source
|
|||
|
registers are extended registers. */
|
|||
|
if (dst_class == EXTENDED_REGS
|
|||
|
|| src1_class == src2_class)
|
|||
|
return \"add %2,%1,%0\";
|
|||
|
|
|||
|
/* It is better to copy one of the sources to the destination, then
|
|||
|
perform a 2 address add. The destination in this case must be
|
|||
|
an address or data register and one of the sources must be an
|
|||
|
extended register and the remaining source must not be an extended
|
|||
|
register.
|
|||
|
|
|||
|
The best code for this case is to copy the extended reg to the
|
|||
|
destination, then emit a two address add. */
|
|||
|
if (src1_class == EXTENDED_REGS)
|
|||
|
return \"mov %1,%0\;add %2,%0\";
|
|||
|
return \"mov %2,%0\;add %1,%0\";
|
|||
|
}
|
|||
|
default:
|
|||
|
gcc_unreachable ();
|
|||
|
}
|
|||
|
}"
|
|||
|
[(set_attr "cc" "set_zn,none_0hit,set_zn,none_0hit,set_zn,none_0hit,set_zn")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=dx,a,a,dax,!*y,!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\";
|
|||
|
default:
|
|||
|
gcc_unreachable ();
|
|||
|
}
|
|||
|
}"
|
|||
|
[(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,!dax")
|
|||
|
(minus:SI (match_operand:SI 1 "register_operand" "0,dax")
|
|||
|
(match_operand:SI 2 "nonmemory_operand" "daxi,dax")))]
|
|||
|
"TARGET_AM33"
|
|||
|
"*
|
|||
|
{
|
|||
|
if (true_regnum (operands[0]) == true_regnum (operands[1]))
|
|||
|
return \"sub %2,%0\";
|
|||
|
else
|
|||
|
{
|
|||
|
enum reg_class src1_class, src2_class, dst_class;
|
|||
|
|
|||
|
src1_class = REGNO_REG_CLASS (true_regnum (operands[1]));
|
|||
|
src2_class = REGNO_REG_CLASS (true_regnum (operands[2]));
|
|||
|
dst_class = REGNO_REG_CLASS (true_regnum (operands[0]));
|
|||
|
|
|||
|
/* If no extended registers are used, then the best way to handle
|
|||
|
this is to copy the first source operand into the destination
|
|||
|
and emit a two address subtraction. */
|
|||
|
if (src1_class != EXTENDED_REGS
|
|||
|
&& src2_class != EXTENDED_REGS
|
|||
|
&& dst_class != EXTENDED_REGS
|
|||
|
&& true_regnum (operands[0]) != true_regnum (operands[2]))
|
|||
|
return \"mov %1,%0\;sub %2,%0\";
|
|||
|
return \"sub %2,%1,%0\";
|
|||
|
}
|
|||
|
}"
|
|||
|
[(set_attr "cc" "set_zn")])
|
|||
|
|
|||
|
(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, const0_rtx);
|
|||
|
emit_insn (gen_subsi3 (target, target, operands[1]));
|
|||
|
emit_move_insn (operands[0], target);
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
;; ----------------------------------------------------------------------
|
|||
|
;; MULTIPLY INSTRUCTIONS
|
|||
|
;; ----------------------------------------------------------------------
|
|||
|
|
|||
|
(define_insn "mulsidi3"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=dax")
|
|||
|
(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "dax"))
|
|||
|
(sign_extend:DI (match_operand:SI 2 "register_operand" "dax"))))]
|
|||
|
"TARGET_AM33"
|
|||
|
"mul %1,%2,%H0,%L0"
|
|||
|
[(set_attr "cc" "set_zn")])
|
|||
|
|
|||
|
(define_insn "umulsidi3"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=dax")
|
|||
|
(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "dax"))
|
|||
|
(zero_extend:DI (match_operand:SI 2 "register_operand" "dax"))))]
|
|||
|
"TARGET_AM33"
|
|||
|
"mulu %1,%2,%H0,%L0"
|
|||
|
[(set_attr "cc" "set_zn")])
|
|||
|
|
|||
|
(define_expand "mulsi3"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "")
|
|||
|
(mult:SI (match_operand:SI 1 "register_operand" "")
|
|||
|
(match_operand:SI 2 "register_operand" "")))]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=dx,!dax")
|
|||
|
(mult:SI (match_operand:SI 1 "register_operand" "%0,0")
|
|||
|
(match_operand:SI 2 "nonmemory_operand" "dx,daxi")))]
|
|||
|
"TARGET_AM33"
|
|||
|
"*
|
|||
|
{
|
|||
|
if (TARGET_MULT_BUG)
|
|||
|
return \"nop\;nop\;mul %2,%0\";
|
|||
|
else
|
|||
|
return \"mul %2,%0\";
|
|||
|
}"
|
|||
|
[(set_attr "cc" "set_zn")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(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 "nonimmediate_operand" "=dx")
|
|||
|
(udiv:SI (match_operand:SI 1 "general_operand" "0")
|
|||
|
(match_operand:SI 2 "general_operand" "dx")))
|
|||
|
(set (match_operand:SI 3 "nonimmediate_operand" "=&d")
|
|||
|
(umod:SI (match_dup 1) (match_dup 2)))]
|
|||
|
""
|
|||
|
"*
|
|||
|
{
|
|||
|
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 "nonimmediate_operand" "=dx")
|
|||
|
(div:SI (match_operand:SI 1 "general_operand" "0")
|
|||
|
(match_operand:SI 2 "general_operand" "dx")))
|
|||
|
(set (match_operand:SI 3 "nonimmediate_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_expand "andsi3"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "")
|
|||
|
(and:SI (match_operand:SI 1 "register_operand" "")
|
|||
|
(match_operand:SI 2 "nonmemory_operand" "")))]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=dx,dx,!dax")
|
|||
|
(and:SI (match_operand:SI 1 "register_operand" "%0,0,dax")
|
|||
|
(match_operand:SI 2 "nonmemory_operand" "N,dxi,dax")))]
|
|||
|
"TARGET_AM33"
|
|||
|
"*
|
|||
|
{
|
|||
|
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\";
|
|||
|
if (REG_P (operands[2]) && REG_P (operands[1])
|
|||
|
&& true_regnum (operands[0]) != true_regnum (operands[1])
|
|||
|
&& true_regnum (operands[0]) != true_regnum (operands[2])
|
|||
|
&& REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
|
|||
|
&& REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
|
|||
|
&& REGNO_REG_CLASS (true_regnum (operands[2])) == DATA_REGS)
|
|||
|
return \"mov %1,%0\;and %2,%0\";
|
|||
|
if (REG_P (operands[2]) && REG_P (operands[1])
|
|||
|
&& true_regnum (operands[0]) != true_regnum (operands[1])
|
|||
|
&& true_regnum (operands[0]) != true_regnum (operands[2]))
|
|||
|
return \"and %1,%2,%0\";
|
|||
|
if (REG_P (operands[2]) && REG_P (operands[0])
|
|||
|
&& true_regnum (operands[2]) == true_regnum (operands[0]))
|
|||
|
return \"and %1,%0\";
|
|||
|
return \"and %2,%0\";
|
|||
|
}"
|
|||
|
[(set (attr "cc")
|
|||
|
(cond
|
|||
|
[
|
|||
|
(eq (symbol_ref "which_alternative") (const_int 0)
|
|||
|
) (const_string "none_0hit")
|
|||
|
(ne (symbol_ref "GET_CODE (operands[2]) == CONST_INT
|
|||
|
&& (INTVAL (operands[2]) == 0x7fffffff
|
|||
|
|| INTVAL (operands[2]) == 0x3fffffff
|
|||
|
|| INTVAL (operands[2]) == 0x1fffffff
|
|||
|
|| INTVAL (operands[2]) == 0x0fffffff
|
|||
|
|| INTVAL (operands[2]) == 0xfffffffe
|
|||
|
|| INTVAL (operands[2]) == 0xfffffffc
|
|||
|
|| INTVAL (operands[2]) == 0xfffffff8
|
|||
|
|| INTVAL (operands[2]) == 0xfffffff0)")
|
|||
|
(const_int 0)) (const_string "set_zn")
|
|||
|
] (const_string "set_znv")))])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(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")
|
|||
|
(cond
|
|||
|
[
|
|||
|
(eq (symbol_ref "which_alternative") (const_int 0)
|
|||
|
) (const_string "none_0hit")
|
|||
|
;; Shifts don't set the V flag, but bitwise operations clear
|
|||
|
;; it (which correctly reflects the absence of overflow in a
|
|||
|
;; compare-with-zero that might follow). As for the
|
|||
|
;; 0xfffffffe case, the add may overflow, so we can't use the
|
|||
|
;; V flag.
|
|||
|
(ne (symbol_ref "GET_CODE (operands[2]) == CONST_INT
|
|||
|
&& (INTVAL (operands[2]) == 0x7fffffff
|
|||
|
|| INTVAL (operands[2]) == 0x3fffffff
|
|||
|
|| INTVAL (operands[2]) == 0x1fffffff
|
|||
|
|| INTVAL (operands[2]) == 0x0fffffff
|
|||
|
|| INTVAL (operands[2]) == 0xfffffffe
|
|||
|
|| INTVAL (operands[2]) == 0xfffffffc
|
|||
|
|| INTVAL (operands[2]) == 0xfffffff8
|
|||
|
|| INTVAL (operands[2]) == 0xfffffff0)")
|
|||
|
(const_int 0)) (const_string "set_zn")
|
|||
|
] (const_string "set_znv")))])
|
|||
|
|
|||
|
;; ----------------------------------------------------------------------
|
|||
|
;; OR INSTRUCTIONS
|
|||
|
;; ----------------------------------------------------------------------
|
|||
|
|
|||
|
(define_expand "iorsi3"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "")
|
|||
|
(ior:SI (match_operand:SI 1 "register_operand" "")
|
|||
|
(match_operand:SI 2 "nonmemory_operand" "")))]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=dx,!dax")
|
|||
|
(ior:SI (match_operand:SI 1 "register_operand" "%0,dax")
|
|||
|
(match_operand:SI 2 "nonmemory_operand" "dxi,dax")))]
|
|||
|
"TARGET_AM33"
|
|||
|
"*
|
|||
|
{
|
|||
|
if (REG_P (operands[2]) && REG_P (operands[1])
|
|||
|
&& true_regnum (operands[0]) != true_regnum (operands[1])
|
|||
|
&& true_regnum (operands[0]) != true_regnum (operands[2])
|
|||
|
&& REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
|
|||
|
&& REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
|
|||
|
&& REGNO_REG_CLASS (true_regnum (operands[2])) == DATA_REGS)
|
|||
|
return \"mov %1,%0\;or %2,%0\";
|
|||
|
if (REG_P (operands[2]) && REG_P (operands[1])
|
|||
|
&& true_regnum (operands[0]) != true_regnum (operands[1])
|
|||
|
&& true_regnum (operands[0]) != true_regnum (operands[2]))
|
|||
|
return \"or %1,%2,%0\";
|
|||
|
if (REG_P (operands[2]) && REG_P (operands[0])
|
|||
|
&& true_regnum (operands[2]) == true_regnum (operands[0]))
|
|||
|
return \"or %1,%0\";
|
|||
|
return \"or %2,%0\";
|
|||
|
}"
|
|||
|
[(set_attr "cc" "set_znv")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(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_expand "xorsi3"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "")
|
|||
|
(xor:SI (match_operand:SI 1 "register_operand" "")
|
|||
|
(match_operand:SI 2 "nonmemory_operand" "")))]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=dx,!dax")
|
|||
|
(xor:SI (match_operand:SI 1 "register_operand" "%0,dax")
|
|||
|
(match_operand:SI 2 "nonmemory_operand" "dxi,dax")))]
|
|||
|
"TARGET_AM33"
|
|||
|
"*
|
|||
|
{
|
|||
|
if (REG_P (operands[2]) && REG_P (operands[1])
|
|||
|
&& true_regnum (operands[0]) != true_regnum (operands[1])
|
|||
|
&& true_regnum (operands[0]) != true_regnum (operands[2])
|
|||
|
&& REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
|
|||
|
&& REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
|
|||
|
&& REGNO_REG_CLASS (true_regnum (operands[2])) == DATA_REGS)
|
|||
|
return \"mov %1,%0\;xor %2,%0\";
|
|||
|
if (REG_P (operands[2]) && REG_P (operands[1])
|
|||
|
&& true_regnum (operands[0]) != true_regnum (operands[1])
|
|||
|
&& true_regnum (operands[0]) != true_regnum (operands[2]))
|
|||
|
return \"xor %1,%2,%0\";
|
|||
|
if (REG_P (operands[2]) && REG_P (operands[0])
|
|||
|
&& true_regnum (operands[2]) == true_regnum (operands[0]))
|
|||
|
return \"xor %1,%0\";
|
|||
|
return \"xor %2,%0\";
|
|||
|
}"
|
|||
|
[(set_attr "cc" "set_znv")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(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_expand "one_cmplsi2"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "")
|
|||
|
(not:SI (match_operand:SI 1 "register_operand" "")))]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=dx,!dax")
|
|||
|
(not:SI (match_operand:SI 1 "register_operand" "0,0")))]
|
|||
|
"TARGET_AM33"
|
|||
|
"not %0"
|
|||
|
[(set_attr "cc" "set_znv")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(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 "nonimmediate_operand" "=R,d") (const_int 0))]
|
|||
|
""
|
|||
|
"@
|
|||
|
bclr 255,%A0
|
|||
|
clr %0"
|
|||
|
[(set_attr "cc" "clobber")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:QI 0 "nonimmediate_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 "nonimmediate_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 "memory_operand" "=R,T")
|
|||
|
(and:QI
|
|||
|
(match_dup 0)
|
|||
|
(not:QI (match_operand:QI 1 "nonmemory_operand" "i,d"))))]
|
|||
|
""
|
|||
|
"@
|
|||
|
bclr %U1,%A0
|
|||
|
bclr %1,%0"
|
|||
|
[(set_attr "cc" "clobber,clobber")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:QI 0 "nonimmediate_operand" "+R,d")
|
|||
|
(subreg:QI
|
|||
|
(ior:SI (subreg:SI (match_dup 0) 0)
|
|||
|
(match_operand:SI 1 "const_int_operand" "i,i")) 0))]
|
|||
|
""
|
|||
|
"@
|
|||
|
bset %U1,%A0
|
|||
|
or %1,%0"
|
|||
|
[(set_attr "cc" "clobber,set_znv")])
|
|||
|
|
|||
|
(define_expand "iorqi3"
|
|||
|
[(set (match_operand:QI 0 "nonimmediate_operand" "")
|
|||
|
(ior:QI (match_operand:QI 1 "nonimmediate_operand" "")
|
|||
|
(match_operand:QI 2 "nonmemory_operand" "")))]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:QI 0 "nonimmediate_operand" "=R,T,r")
|
|||
|
(ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0")
|
|||
|
;; This constraint should really be nonmemory_operand,
|
|||
|
;; but making it general_operand, along with the
|
|||
|
;; condition that not both input operands are MEMs, it
|
|||
|
;; here helps combine do a better job.
|
|||
|
(match_operand:QI 2 "general_operand" "i,d,ir")))]
|
|||
|
"TARGET_AM33 &&
|
|||
|
(GET_CODE (operands[2]) != MEM || GET_CODE (operands[1]) != MEM)"
|
|||
|
"@
|
|||
|
bset %U2,%A0
|
|||
|
bset %2,%0
|
|||
|
or %2,%0"
|
|||
|
[(set_attr "cc" "clobber,clobber,set_znv")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:QI 0 "nonimmediate_operand" "=R,T,d")
|
|||
|
(ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0")
|
|||
|
;; This constraint should really be nonmemory_operand,
|
|||
|
;; but making it general_operand, along with the
|
|||
|
;; condition that not both input operands are MEMs, it
|
|||
|
;; here helps combine do a better job.
|
|||
|
(match_operand:QI 2 "general_operand" "i,d,id")))]
|
|||
|
"GET_CODE (operands[2]) != MEM || GET_CODE (operands[1]) != MEM"
|
|||
|
"@
|
|||
|
bset %U2,%A0
|
|||
|
bset %2,%0
|
|||
|
or %2,%0"
|
|||
|
[(set_attr "cc" "clobber,clobber,set_znv")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (cc0)
|
|||
|
(compare (zero_extract:SI (match_operand:SI 0 "register_operand" "dx")
|
|||
|
(match_operand 1 "const_int_operand" "")
|
|||
|
(match_operand 2 "const_int_operand" ""))
|
|||
|
(const_int 0)))]
|
|||
|
""
|
|||
|
"*
|
|||
|
{
|
|||
|
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 (trunc_int_for_mode (mask, SImode));
|
|||
|
output_asm_insn (\"btst %1,%0\", xoperands);
|
|||
|
return \"\";
|
|||
|
}"
|
|||
|
[(set_attr "cc" "clobber")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (cc0)
|
|||
|
(compare (zero_extract:SI (match_operand:QI 0 "general_operand" "R,dx")
|
|||
|
(match_operand 1 "const_int_operand" "")
|
|||
|
(match_operand 2 "const_int_operand" ""))
|
|||
|
(const_int 0)))]
|
|||
|
"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 (i.e. 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 (trunc_int_for_mode (mask, SImode));
|
|||
|
if (GET_CODE (operands[0]) == REG)
|
|||
|
output_asm_insn (\"btst %1,%0\", xoperands);
|
|||
|
else
|
|||
|
output_asm_insn (\"btst %U1,%A0\", xoperands);
|
|||
|
return \"\";
|
|||
|
}"
|
|||
|
[(set_attr "cc" "clobber")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (cc0) (compare (and:SI (match_operand:SI 0 "register_operand" "dx")
|
|||
|
(match_operand:SI 1 "const_int_operand" ""))
|
|||
|
(const_int 0)))]
|
|||
|
""
|
|||
|
"btst %1,%0"
|
|||
|
[(set_attr "cc" "clobber")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (cc0)
|
|||
|
(compare (and:SI
|
|||
|
(subreg:SI (match_operand:QI 0 "general_operand" "R,dx") 0)
|
|||
|
(match_operand:SI 1 "const_8bit_operand" ""))
|
|||
|
(const_int 0)))]
|
|||
|
""
|
|||
|
"@
|
|||
|
btst %U1,%A0
|
|||
|
btst %1,%0"
|
|||
|
[(set_attr "cc" "clobber")])
|
|||
|
|
|||
|
|
|||
|
;; ----------------------------------------------------------------------
|
|||
|
;; JUMP INSTRUCTIONS
|
|||
|
;; ----------------------------------------------------------------------
|
|||
|
|
|||
|
(define_expand "cbranchsi4"
|
|||
|
[(set (cc0)
|
|||
|
(compare (match_operand:SI 1 "register_operand" "")
|
|||
|
(match_operand:SI 2 "nonmemory_operand" "")))
|
|||
|
(set (pc)
|
|||
|
(if_then_else
|
|||
|
(match_operator 0 "ordered_comparison_operator" [(cc0)
|
|||
|
(const_int 0)])
|
|||
|
(label_ref (match_operand 3 "" ""))
|
|||
|
(pc)))]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
(define_expand "cbranchsf4"
|
|||
|
[(set (cc0)
|
|||
|
(compare (match_operand:SF 1 "register_operand" "")
|
|||
|
(match_operand:SF 2 "nonmemory_operand" "")))
|
|||
|
(set (pc)
|
|||
|
(if_then_else
|
|||
|
(match_operator 0 "ordered_comparison_operator" [(cc0)
|
|||
|
(const_int 0)])
|
|||
|
(label_ref (match_operand 3 "" ""))
|
|||
|
(pc)))]
|
|||
|
"TARGET_AM33_2"
|
|||
|
"")
|
|||
|
|
|||
|
|
|||
|
;; Conditional jump instructions
|
|||
|
|
|||
|
(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.mdep.fpCC)
|
|||
|
return \"fb%b1 %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")])
|
|||
|
|
|||
|
(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.mdep.fpCC)
|
|||
|
return \"fb%B1 %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_expand "builtin_setjmp_receiver"
|
|||
|
[(match_operand 0 "" "")]
|
|||
|
"flag_pic"
|
|||
|
"
|
|||
|
{
|
|||
|
if (flag_pic)
|
|||
|
emit_insn (gen_GOTaddr2picreg ());
|
|||
|
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
(define_expand "casesi"
|
|||
|
[(match_operand:SI 0 "register_operand" "")
|
|||
|
(match_operand:SI 1 "immediate_operand" "")
|
|||
|
(match_operand:SI 2 "immediate_operand" "")
|
|||
|
(match_operand 3 "" "") (match_operand 4 "" "")]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
rtx table = gen_reg_rtx (SImode);
|
|||
|
rtx index = gen_reg_rtx (SImode);
|
|||
|
rtx addr = gen_reg_rtx (Pmode);
|
|||
|
rtx test;
|
|||
|
|
|||
|
emit_move_insn (table, gen_rtx_LABEL_REF (VOIDmode, operands[3]));
|
|||
|
emit_move_insn (index, plus_constant (operands[0], - INTVAL (operands[1])));
|
|||
|
test = gen_rtx_fmt_ee (GTU, VOIDmode, index, operands[2]);
|
|||
|
emit_jump_insn (gen_cbranchsi4 (test, index, operands[2], operands[4]));
|
|||
|
|
|||
|
emit_move_insn (index, gen_rtx_ASHIFT (SImode, index, const2_rtx));
|
|||
|
emit_move_insn (addr, gen_rtx_MEM (SImode,
|
|||
|
gen_rtx_PLUS (SImode, table, index)));
|
|||
|
if (flag_pic)
|
|||
|
emit_move_insn (addr, gen_rtx_PLUS (SImode, addr, table));
|
|||
|
|
|||
|
emit_jump_insn (gen_tablejump (addr, operands[3]));
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
(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 (flag_pic && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF)
|
|||
|
{
|
|||
|
if (MN10300_GLOBAL_P (XEXP (operands[0], 0)))
|
|||
|
{
|
|||
|
/* The PLT code won't run on AM30, but then, there's no
|
|||
|
shared library support for AM30 either, so we just assume
|
|||
|
the linker is going to adjust all @PLT relocs to the
|
|||
|
actual symbols. */
|
|||
|
emit_use (pic_offset_table_rtx);
|
|||
|
XEXP (operands[0], 0) = gen_sym2PLT (XEXP (operands[0], 0));
|
|||
|
}
|
|||
|
else
|
|||
|
XEXP (operands[0], 0) = gen_sym2PIC (XEXP (operands[0], 0));
|
|||
|
}
|
|||
|
if (! call_address_operand (XEXP (operands[0], 0), VOIDmode))
|
|||
|
XEXP (operands[0], 0) = force_reg (SImode, XEXP (operands[0], 0));
|
|||
|
emit_call_insn (gen_call_internal (XEXP (operands[0], 0), operands[1]));
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
;; NB: Mode on match_operand 0 deliberately omitted in
|
|||
|
;; order to be able to match UNSPECs in PIC mode.
|
|||
|
(define_insn "call_internal"
|
|||
|
[(call (mem:QI (match_operand 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 (flag_pic && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF)
|
|||
|
{
|
|||
|
if (MN10300_GLOBAL_P (XEXP (operands[1], 0)))
|
|||
|
{
|
|||
|
/* The PLT code won't run on AM30, but then, there's no
|
|||
|
shared library support for AM30 either, so we just assume
|
|||
|
the linker is going to adjust all @PLT relocs to the
|
|||
|
actual symbols. */
|
|||
|
emit_use (pic_offset_table_rtx);
|
|||
|
XEXP (operands[1], 0) = gen_sym2PLT (XEXP (operands[1], 0));
|
|||
|
}
|
|||
|
else
|
|||
|
XEXP (operands[1], 0) = gen_sym2PIC (XEXP (operands[1], 0));
|
|||
|
}
|
|||
|
if (! call_address_operand (XEXP (operands[1], 0), VOIDmode))
|
|||
|
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;
|
|||
|
}")
|
|||
|
|
|||
|
;; NB: Mode on match_operands 0 and 1 deliberately omitted
|
|||
|
;; in order to be able to match UNSPECs in PIC mode.
|
|||
|
(define_insn "call_value_internal"
|
|||
|
[(set (match_operand 0 "register_operand" "=dax")
|
|||
|
(call (mem:QI (match_operand 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_expand "zero_extendqisi2"
|
|||
|
[(set (match_operand:SI 0 "general_operand" "")
|
|||
|
(zero_extend:SI
|
|||
|
(match_operand:QI 1 "general_operand" "")))]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "nonimmediate_operand" "=dx,dx,dx,!dax,!dax,!dax")
|
|||
|
(zero_extend:SI
|
|||
|
(match_operand:QI 1 "general_operand" "0,dax,m,0,dax,m")))]
|
|||
|
"TARGET_AM33"
|
|||
|
"@
|
|||
|
extbu %0
|
|||
|
mov %1,%0\;extbu %0
|
|||
|
movbu %1,%0
|
|||
|
extbu %0
|
|||
|
mov %1,%0\;extbu %0
|
|||
|
movbu %1,%0"
|
|||
|
[(set_attr "cc" "none_0hit")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "nonimmediate_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_expand "zero_extendhisi2"
|
|||
|
[(set (match_operand:SI 0 "general_operand" "")
|
|||
|
(zero_extend:SI
|
|||
|
(match_operand:HI 1 "general_operand" "")))]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "nonimmediate_operand" "=dx,dx,dx,!dax,!dax,!dax")
|
|||
|
(zero_extend:SI
|
|||
|
(match_operand:HI 1 "general_operand" "0,dax,m,0,dax,m")))]
|
|||
|
"TARGET_AM33"
|
|||
|
"@
|
|||
|
exthu %0
|
|||
|
mov %1,%0\;exthu %0
|
|||
|
movhu %1,%0
|
|||
|
exthu %0
|
|||
|
mov %1,%0\;exthu %0
|
|||
|
movhu %1,%0"
|
|||
|
[(set_attr "cc" "none_0hit")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "nonimmediate_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_expand "extendqisi2"
|
|||
|
[(set (match_operand:SI 0 "general_operand" "")
|
|||
|
(sign_extend:SI
|
|||
|
(match_operand:QI 1 "general_operand" "")))]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "nonimmediate_operand" "=dx,dx,!dax,!dax")
|
|||
|
(sign_extend:SI
|
|||
|
(match_operand:QI 1 "general_operand" "0,dx,0,dax")))]
|
|||
|
"TARGET_AM33"
|
|||
|
"@
|
|||
|
extb %0
|
|||
|
mov %1,%0\;extb %0
|
|||
|
extb %0
|
|||
|
mov %1,%0\;extb %0"
|
|||
|
[(set_attr "cc" "none_0hit")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "nonimmediate_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_expand "extendhisi2"
|
|||
|
[(set (match_operand:SI 0 "general_operand" "")
|
|||
|
(sign_extend:SI
|
|||
|
(match_operand:HI 1 "general_operand" "")))]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "nonimmediate_operand" "=dx,dx,!dax,!dax")
|
|||
|
(sign_extend:SI
|
|||
|
(match_operand:HI 1 "general_operand" "0,dax,0,dax")))]
|
|||
|
"TARGET_AM33"
|
|||
|
"@
|
|||
|
exth %0
|
|||
|
mov %1,%0\;exth %0
|
|||
|
exth %0
|
|||
|
mov %1,%0\;exth %0"
|
|||
|
[(set_attr "cc" "none_0hit")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "nonimmediate_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_expand "ashlsi3"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "")
|
|||
|
(ashift:SI
|
|||
|
(match_operand:SI 1 "register_operand" "")
|
|||
|
(match_operand:QI 2 "nonmemory_operand" "")))]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=dax,dx,!dax")
|
|||
|
(ashift:SI
|
|||
|
(match_operand:SI 1 "register_operand" "0,0,dax")
|
|||
|
(match_operand:QI 2 "nonmemory_operand" "J,dxi,dax")))]
|
|||
|
"TARGET_AM33"
|
|||
|
"*
|
|||
|
{
|
|||
|
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 1)
|
|||
|
return \"add %0,%0\";
|
|||
|
|
|||
|
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 2)
|
|||
|
return \"asl2 %0\";
|
|||
|
|
|||
|
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 3
|
|||
|
&& REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS)
|
|||
|
return \"asl2 %0\;add %0,%0\";
|
|||
|
|
|||
|
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 4
|
|||
|
&& REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS)
|
|||
|
return \"asl2 %0\;asl2 %0\";
|
|||
|
|
|||
|
if (true_regnum (operands[1]) == true_regnum (operands[0]))
|
|||
|
return \"asl %S2,%0\";
|
|||
|
|
|||
|
if (REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
|
|||
|
&& REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
|
|||
|
&& true_regnum (operands[0]) != true_regnum (operands[2]))
|
|||
|
return \"mov %1,%0\;asl %S2,%0\";
|
|||
|
return \"asl %2,%1,%0\";
|
|||
|
}"
|
|||
|
[(set_attr "cc" "set_zn")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(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_expand "lshrsi3"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "")
|
|||
|
(lshiftrt:SI
|
|||
|
(match_operand:SI 1 "register_operand" "")
|
|||
|
(match_operand:QI 2 "nonmemory_operand" "")))]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=dx,!dax")
|
|||
|
(lshiftrt:SI
|
|||
|
(match_operand:SI 1 "register_operand" "0,dax")
|
|||
|
(match_operand:QI 2 "nonmemory_operand" "dxi,dax")))]
|
|||
|
"TARGET_AM33"
|
|||
|
"*
|
|||
|
{
|
|||
|
if (true_regnum (operands[1]) == true_regnum (operands[0]))
|
|||
|
return \"lsr %S2,%0\";
|
|||
|
|
|||
|
if (REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
|
|||
|
&& REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
|
|||
|
&& true_regnum (operands[0]) != true_regnum (operands[2]))
|
|||
|
return \"mov %1,%0\;lsr %S2,%0\";
|
|||
|
return \"lsr %2,%1,%0\";
|
|||
|
}"
|
|||
|
[(set_attr "cc" "set_zn")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(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_expand "ashrsi3"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "")
|
|||
|
(ashiftrt:SI
|
|||
|
(match_operand:SI 1 "register_operand" "")
|
|||
|
(match_operand:QI 2 "nonmemory_operand" "")))]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=dx,!dax")
|
|||
|
(ashiftrt:SI
|
|||
|
(match_operand:SI 1 "register_operand" "0,dax")
|
|||
|
(match_operand:QI 2 "nonmemory_operand" "dxi,dax")))]
|
|||
|
"TARGET_AM33"
|
|||
|
"*
|
|||
|
{
|
|||
|
if (true_regnum (operands[1]) == true_regnum (operands[0]))
|
|||
|
return \"asr %S2,%0\";
|
|||
|
|
|||
|
if (REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
|
|||
|
&& REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
|
|||
|
&& true_regnum (operands[0]) != true_regnum (operands[2]))
|
|||
|
return \"mov %1,%0\;asr %S2,%0\";
|
|||
|
return \"asr %2,%1,%0\";
|
|||
|
}"
|
|||
|
[(set_attr "cc" "set_zn")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(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")])
|
|||
|
|
|||
|
;; ----------------------------------------------------------------------
|
|||
|
;; FP INSTRUCTIONS
|
|||
|
;; ----------------------------------------------------------------------
|
|||
|
;;
|
|||
|
;; The mn103 series does not have floating point instructions, but since
|
|||
|
;; FP values are held in integer regs, we can clear the high bit easily
|
|||
|
;; which gives us an efficient inline floating point absolute value.
|
|||
|
;;
|
|||
|
;; Similarly for negation of a FP value.
|
|||
|
;;
|
|||
|
|
|||
|
(define_expand "absdf2"
|
|||
|
[(set (match_operand:DF 0 "register_operand" "")
|
|||
|
(abs:DF (match_operand:DF 1 "register_operand" "")))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
rtx target, result, insns;
|
|||
|
|
|||
|
start_sequence ();
|
|||
|
target = operand_subword (operands[0], 1, 1, DFmode);
|
|||
|
result = expand_binop (SImode, and_optab,
|
|||
|
operand_subword_force (operands[1], 1, DFmode),
|
|||
|
GEN_INT (0x7fffffff), target, 0, OPTAB_WIDEN);
|
|||
|
|
|||
|
gcc_assert (result);
|
|||
|
|
|||
|
if (result != target)
|
|||
|
emit_move_insn (result, target);
|
|||
|
|
|||
|
emit_move_insn (operand_subword (operands[0], 0, 1, DFmode),
|
|||
|
operand_subword_force (operands[1], 0, DFmode));
|
|||
|
|
|||
|
insns = get_insns ();
|
|||
|
end_sequence ();
|
|||
|
|
|||
|
emit_insn (insns);
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
(define_expand "abssf2"
|
|||
|
[(set (match_operand:SF 0 "register_operand" "")
|
|||
|
(abs:SF (match_operand:SF 1 "register_operand" "")))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
rtx result;
|
|||
|
rtx target;
|
|||
|
|
|||
|
if (TARGET_AM33_2)
|
|||
|
{
|
|||
|
emit_insn (gen_abssf2_am33_2 (operands[0], operands[1]));
|
|||
|
DONE;
|
|||
|
}
|
|||
|
|
|||
|
target = operand_subword_force (operands[0], 0, SFmode);
|
|||
|
result = expand_binop (SImode, and_optab,
|
|||
|
operand_subword_force (operands[1], 0, SFmode),
|
|||
|
GEN_INT (0x7fffffff), target, 0, OPTAB_WIDEN);
|
|||
|
gcc_assert (result);
|
|||
|
|
|||
|
if (result != target)
|
|||
|
emit_move_insn (result, target);
|
|||
|
|
|||
|
/* Make a place for REG_EQUAL. */
|
|||
|
emit_move_insn (operands[0], operands[0]);
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
|
|||
|
(define_insn "abssf2_am33_2"
|
|||
|
[(set (match_operand:SF 0 "register_operand" "=f,f")
|
|||
|
(abs:SF (match_operand:SF 1 "register_operand" "0,?f")))]
|
|||
|
"TARGET_AM33_2"
|
|||
|
"@
|
|||
|
fabs %0
|
|||
|
fabs %1, %0"
|
|||
|
[(set_attr "cc" "none_0hit")])
|
|||
|
|
|||
|
(define_expand "negdf2"
|
|||
|
[(set (match_operand:DF 0 "register_operand" "")
|
|||
|
(neg:DF (match_operand:DF 1 "register_operand" "")))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
rtx target, result, insns;
|
|||
|
|
|||
|
start_sequence ();
|
|||
|
target = operand_subword (operands[0], 1, 1, DFmode);
|
|||
|
result = expand_binop (SImode, xor_optab,
|
|||
|
operand_subword_force (operands[1], 1, DFmode),
|
|||
|
GEN_INT (trunc_int_for_mode (0x80000000, SImode)),
|
|||
|
target, 0, OPTAB_WIDEN);
|
|||
|
|
|||
|
gcc_assert (result);
|
|||
|
|
|||
|
if (result != target)
|
|||
|
emit_move_insn (result, target);
|
|||
|
|
|||
|
emit_move_insn (operand_subword (operands[0], 0, 1, DFmode),
|
|||
|
operand_subword_force (operands[1], 0, DFmode));
|
|||
|
|
|||
|
insns = get_insns ();
|
|||
|
end_sequence ();
|
|||
|
|
|||
|
emit_insn (insns);
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
(define_expand "negsf2"
|
|||
|
[(set (match_operand:SF 0 "register_operand" "")
|
|||
|
(neg:SF (match_operand:SF 1 "register_operand" "")))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
rtx result;
|
|||
|
rtx target;
|
|||
|
|
|||
|
if (TARGET_AM33_2)
|
|||
|
{
|
|||
|
emit_insn (gen_negsf2_am33_2 (operands[0], operands[1]));
|
|||
|
DONE;
|
|||
|
}
|
|||
|
|
|||
|
target = operand_subword_force (operands[0], 0, SFmode);
|
|||
|
result = expand_binop (SImode, xor_optab,
|
|||
|
operand_subword_force (operands[1], 0, SFmode),
|
|||
|
GEN_INT (trunc_int_for_mode (0x80000000, SImode)),
|
|||
|
target, 0, OPTAB_WIDEN);
|
|||
|
gcc_assert (result);
|
|||
|
|
|||
|
if (result != target)
|
|||
|
emit_move_insn (result, target);
|
|||
|
|
|||
|
/* Make a place for REG_EQUAL. */
|
|||
|
emit_move_insn (operands[0], operands[0]);
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
(define_insn "negsf2_am33_2"
|
|||
|
[(set (match_operand:SF 0 "register_operand" "=f,f")
|
|||
|
(neg:SF (match_operand:SF 1 "register_operand" "0,?f")))]
|
|||
|
"TARGET_AM33_2"
|
|||
|
"@
|
|||
|
fneg %0
|
|||
|
fneg %1, %0"
|
|||
|
[(set_attr "cc" "none_0hit")])
|
|||
|
|
|||
|
(define_expand "sqrtsf2"
|
|||
|
[(set (match_operand:SF 0 "register_operand" "")
|
|||
|
(sqrt:SF (match_operand:SF 1 "register_operand" "")))]
|
|||
|
"TARGET_AM33_2 && flag_unsafe_math_optimizations"
|
|||
|
"
|
|||
|
{
|
|||
|
rtx scratch = gen_reg_rtx (SFmode);
|
|||
|
emit_insn (gen_rsqrtsf2 (scratch, operands[1], CONST1_RTX (SFmode)));
|
|||
|
emit_insn (gen_divsf3 (operands[0], force_reg (SFmode, CONST1_RTX (SFmode)),
|
|||
|
scratch));
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
(define_insn "rsqrtsf2"
|
|||
|
[(set (match_operand:SF 0 "register_operand" "=f,f")
|
|||
|
(div:SF (match_operand:SF 2 "const_1f_operand" "F,F")
|
|||
|
(sqrt:SF (match_operand:SF 1 "register_operand" "0,?f"))))]
|
|||
|
"TARGET_AM33_2"
|
|||
|
"@
|
|||
|
frsqrt %0
|
|||
|
frsqrt %1, %0"
|
|||
|
[(set_attr "cc" "none_0hit")])
|
|||
|
|
|||
|
(define_insn "addsf3"
|
|||
|
[(set (match_operand:SF 0 "register_operand" "=f,f")
|
|||
|
(plus:SF (match_operand:SF 1 "register_operand" "%0,f")
|
|||
|
(match_operand:SF 2 "general_operand" "f,?fF")))]
|
|||
|
"TARGET_AM33_2"
|
|||
|
"@
|
|||
|
fadd %2, %0
|
|||
|
fadd %2, %1, %0"
|
|||
|
[(set_attr "cc" "none_0hit")])
|
|||
|
|
|||
|
(define_insn "subsf3"
|
|||
|
[(set (match_operand:SF 0 "register_operand" "=f,f")
|
|||
|
(minus:SF (match_operand:SF 1 "register_operand" "0,f")
|
|||
|
(match_operand:SF 2 "general_operand" "f,?fF")))]
|
|||
|
"TARGET_AM33_2"
|
|||
|
"@
|
|||
|
fsub %2, %0
|
|||
|
fsub %2, %1, %0"
|
|||
|
[(set_attr "cc" "none_0hit")])
|
|||
|
|
|||
|
(define_insn "mulsf3"
|
|||
|
[(set (match_operand:SF 0 "register_operand" "=f,f")
|
|||
|
(mult:SF (match_operand:SF 1 "register_operand" "%0,f")
|
|||
|
(match_operand:SF 2 "general_operand" "f,?fF")))]
|
|||
|
"TARGET_AM33_2"
|
|||
|
"@
|
|||
|
fmul %2, %0
|
|||
|
fmul %2, %1, %0"
|
|||
|
[(set_attr "cc" "none_0hit")])
|
|||
|
|
|||
|
(define_insn "divsf3"
|
|||
|
[(set (match_operand:SF 0 "register_operand" "=f,f")
|
|||
|
(div:SF (match_operand:SF 1 "register_operand" "0,f")
|
|||
|
(match_operand:SF 2 "general_operand" "f,?fF")))]
|
|||
|
"TARGET_AM33_2"
|
|||
|
"@
|
|||
|
fdiv %2, %0
|
|||
|
fdiv %2, %1, %0"
|
|||
|
[(set_attr "cc" "none_0hit")])
|
|||
|
|
|||
|
(define_insn "fmaddsf4"
|
|||
|
[(set (match_operand:SF 0 "register_operand" "=A")
|
|||
|
(plus:SF (mult:SF (match_operand:SF 1 "register_operand" "%f")
|
|||
|
(match_operand:SF 2 "register_operand" "f"))
|
|||
|
(match_operand:SF 3 "register_operand" "f")))]
|
|||
|
"TARGET_AM33_2"
|
|||
|
"fmadd %1, %2, %3, %0"
|
|||
|
[(set_attr "cc" "none_0hit")])
|
|||
|
|
|||
|
(define_insn "fmsubsf4"
|
|||
|
[(set (match_operand:SF 0 "register_operand" "=A")
|
|||
|
(minus:SF (mult:SF (match_operand:SF 1 "register_operand" "%f")
|
|||
|
(match_operand:SF 2 "register_operand" "f"))
|
|||
|
(match_operand:SF 3 "register_operand" "f")))]
|
|||
|
"TARGET_AM33_2"
|
|||
|
"fmsub %1, %2, %3, %0"
|
|||
|
[(set_attr "cc" "none_0hit")])
|
|||
|
|
|||
|
(define_insn "fnmaddsf4"
|
|||
|
[(set (match_operand:SF 0 "register_operand" "=A")
|
|||
|
(minus:SF (match_operand:SF 3 "register_operand" "f")
|
|||
|
(mult:SF (match_operand:SF 1 "register_operand" "%f")
|
|||
|
(match_operand:SF 2 "register_operand" "f"))))]
|
|||
|
"TARGET_AM33_2"
|
|||
|
"fnmadd %1, %2, %3, %0"
|
|||
|
[(set_attr "cc" "none_0hit")])
|
|||
|
|
|||
|
(define_insn "fnmsubsf4"
|
|||
|
[(set (match_operand:SF 0 "register_operand" "=A")
|
|||
|
(minus:SF (neg:SF (mult:SF (match_operand:SF 1 "register_operand" "%f")
|
|||
|
(match_operand:SF 2 "register_operand" "f")))
|
|||
|
(match_operand:SF 3 "register_operand" "f")))]
|
|||
|
"TARGET_AM33_2"
|
|||
|
"fnmsub %1, %2, %3, %0"
|
|||
|
[(set_attr "cc" "none_0hit")])
|
|||
|
|
|||
|
|
|||
|
;; ----------------------------------------------------------------------
|
|||
|
;; 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)
|
|||
|
(return)]
|
|||
|
""
|
|||
|
"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)]
|
|||
|
""
|
|||
|
"*
|
|||
|
{
|
|||
|
fputs (\"\\tret \", asm_out_file);
|
|||
|
mn10300_print_reg_list (asm_out_file, mn10300_get_live_callee_saved_regs ());
|
|||
|
fprintf (asm_out_file, \",%d\\n\", (int) INTVAL (operands[0]));
|
|||
|
return \"\";
|
|||
|
}"
|
|||
|
[(set_attr "cc" "clobber")])
|
|||
|
|
|||
|
;; This instruction matches one generated by mn10300_gen_multiple_store()
|
|||
|
(define_insn "store_movm"
|
|||
|
[(match_parallel 0 "store_multiple_operation"
|
|||
|
[(set (reg:SI 9) (plus:SI (reg:SI 9) (match_operand 1 "" "")))])]
|
|||
|
""
|
|||
|
"*
|
|||
|
{
|
|||
|
fputs (\"\\tmovm \", asm_out_file);
|
|||
|
mn10300_print_reg_list (asm_out_file,
|
|||
|
store_multiple_operation (operands[0], VOIDmode));
|
|||
|
fprintf (asm_out_file, \",(sp)\\n\");
|
|||
|
return \"\";
|
|||
|
}"
|
|||
|
[(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) (compare (match_operand:SI 0 "register_operand" "dx")
|
|||
|
(const_int 0)))
|
|||
|
(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) (compare (match_operand:SI 0 "register_operand" "dx")
|
|||
|
(const_int 0)))
|
|||
|
(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) (compare (match_operand:SI 0 "register_operand" "dx")
|
|||
|
(const_int 0)))
|
|||
|
(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) (compare (match_operand:SI 0 "register_operand" "dx")
|
|||
|
(const_int 0)))
|
|||
|
(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")])
|
|||
|
|
|||
|
(define_expand "int_label"
|
|||
|
[(unspec [(match_operand:SI 0 "" "")] UNSPEC_INT_LABEL)]
|
|||
|
"" "")
|
|||
|
|
|||
|
(define_expand "GOTaddr2picreg"
|
|||
|
[(match_dup 0)]
|
|||
|
"" "
|
|||
|
{
|
|||
|
/* It would be nice to be able to have int_label keep track of the
|
|||
|
counter and all, but if we add C code to it, we'll get an insn
|
|||
|
back, and we just want the pattern. */
|
|||
|
operands[0] = gen_int_label (GEN_INT (mn10300_unspec_int_label_counter++));
|
|||
|
if (TARGET_AM33)
|
|||
|
emit_insn (gen_am33_loadPC (operands[0]));
|
|||
|
else
|
|||
|
emit_insn (gen_mn10300_loadPC (operands[0]));
|
|||
|
emit_insn (gen_add_GOT_to_pic_reg (copy_rtx (operands[0])));
|
|||
|
DONE;
|
|||
|
}
|
|||
|
")
|
|||
|
|
|||
|
(define_insn "am33_loadPC"
|
|||
|
[(parallel
|
|||
|
[(set (reg:SI PIC_REG) (pc))
|
|||
|
(use (match_operand 0 "" ""))])]
|
|||
|
"TARGET_AM33"
|
|||
|
"%0:\;mov pc,a2")
|
|||
|
|
|||
|
|
|||
|
(define_insn_and_split "mn10300_loadPC"
|
|||
|
[(parallel
|
|||
|
[(set (reg:SI PIC_REG) (pc))
|
|||
|
(use (match_operand 0 "" ""))])]
|
|||
|
""
|
|||
|
"#"
|
|||
|
"reload_completed"
|
|||
|
[(match_operand 0 "" "")]
|
|||
|
"
|
|||
|
{
|
|||
|
rtx sp_reg = gen_rtx_REG (SImode, SP_REG);
|
|||
|
int need_stack_space = (get_frame_size () == 0
|
|||
|
&& crtl->outgoing_args_size == 0);
|
|||
|
|
|||
|
if (need_stack_space)
|
|||
|
emit_move_insn (sp_reg, plus_constant (sp_reg, -4));
|
|||
|
|
|||
|
emit_insn (gen_call_next_insn (operands[0]));
|
|||
|
|
|||
|
if (need_stack_space)
|
|||
|
emit_insn (gen_pop_pic_reg ());
|
|||
|
else
|
|||
|
emit_move_insn (pic_offset_table_rtx, gen_rtx_MEM (SImode, sp_reg));
|
|||
|
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
(define_insn "call_next_insn"
|
|||
|
[(parallel
|
|||
|
[(set (mem:SI (reg:SI SP_REG)) (pc))
|
|||
|
(use (match_operand 0 "" ""))])]
|
|||
|
"reload_completed"
|
|||
|
"calls %0\;%0:")
|
|||
|
|
|||
|
(define_expand "add_GOT_to_pic_reg"
|
|||
|
[(set (reg:SI PIC_REG)
|
|||
|
(plus:SI
|
|||
|
(reg:SI PIC_REG)
|
|||
|
(const:SI
|
|||
|
(unspec:SI [(match_operand:SI 0 "" "")] UNSPEC_GOTSYM_OFF))))]
|
|||
|
"")
|
|||
|
|
|||
|
(define_expand "symGOT2reg"
|
|||
|
[(match_operand:SI 0 "" "")
|
|||
|
(match_operand:SI 1 "" "")]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
rtx insn = emit_insn (gen_symGOT2reg_i (operands[0], operands[1]));
|
|||
|
|
|||
|
MEM_READONLY_P (SET_SRC (PATTERN (insn))) = 1;
|
|||
|
|
|||
|
set_unique_reg_note (insn, REG_EQUAL, operands[1]);
|
|||
|
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
(define_expand "symGOT2reg_i"
|
|||
|
[(set (match_operand:SI 0 "" "")
|
|||
|
(mem:SI (plus:SI (reg:SI PIC_REG)
|
|||
|
(const (unspec [(match_operand:SI 1 "" "")]
|
|||
|
UNSPEC_GOT)))))]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
(define_expand "symGOTOFF2reg"
|
|||
|
[(match_operand:SI 0 "" "") (match_operand:SI 1 "" "")]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
rtx insn = emit_insn (gen_symGOTOFF2reg_i (operands[0], operands[1]));
|
|||
|
|
|||
|
set_unique_reg_note (insn, REG_EQUAL, operands[1]);
|
|||
|
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
(define_expand "symGOTOFF2reg_i"
|
|||
|
[(set (match_operand:SI 0 "" "")
|
|||
|
(const (unspec [(match_operand:SI 1 "" "")] UNSPEC_GOTOFF)))
|
|||
|
(set (match_dup 0) (plus:SI (match_dup 0) (reg:SI PIC_REG)))]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
(define_expand "sym2PIC"
|
|||
|
[(unspec [(match_operand:SI 0 "" "")] UNSPEC_PIC)]
|
|||
|
"" "")
|
|||
|
|
|||
|
(define_expand "sym2PLT"
|
|||
|
[(unspec [(match_operand:SI 0 "" "")] UNSPEC_PLT)]
|
|||
|
"" "")
|