;; GCC machine description for Matsushita MN10300 ;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, ;; 2007 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 ;; . ;; 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) ]) (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,m") (match_operand:QI 1 "general_operand" "0,I,dai,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: 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 3: case 4: return \"movbu %1,%0\"; default: gcc_unreachable (); } }" [(set_attr "cc" "none,clobber,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,m") (match_operand:HI 1 "general_operand" "0,I,dai,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: 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 3: case 4: return \"movhu %1,%0\"; default: gcc_unreachable (); } }" [(set_attr "cc" "none,clobber,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 ;; ---------------------------------------------------------------------- ;; Go ahead and define tstsi so we can eliminate redundant tst insns ;; when we start trying to optimize this port. (define_insn "tstsi" [(set (cc0) (match_operand:SI 0 "register_operand" "dax"))] "" "* return output_tst (operands[0], insn);" [(set_attr "cc" "set_znv")]) (define_insn "" [(set (cc0) (zero_extend:SI (match_operand:QI 0 "memory_operand" "dx,!a")))] "TARGET_AM33" "* return output_tst (operands[0], insn);" [(set_attr "cc" "set_znv")]) (define_insn "" [(set (cc0) (zero_extend:SI (match_operand:QI 0 "memory_operand" "dx")))] "" "* return output_tst (operands[0], insn);" [(set_attr "cc" "set_znv")]) (define_insn "" [(set (cc0) (zero_extend:SI (match_operand:HI 0 "memory_operand" "dx,!a")))] "TARGET_AM33" "* return output_tst (operands[0], insn);" [(set_attr "cc" "set_znv")]) (define_insn "" [(set (cc0) (zero_extend:SI (match_operand:HI 0 "memory_operand" "dx")))] "" "* return output_tst (operands[0], insn);" [(set_attr "cc" "set_znv")]) ;; 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") (match_operand:SI 1 "nonmemory_operand" "*0,daxi")))] "" "@ btst 0,d0 cmp %1,%0" [(set_attr "cc" "compare,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) (zero_extract:SI (match_operand:SI 0 "register_operand" "dx") (match_operand 1 "const_int_operand" "") (match_operand 2 "const_int_operand" "")))] "" "* { int len = INTVAL (operands[1]); int bit = INTVAL (operands[2]); int mask = 0; rtx xoperands[2]; while (len > 0) { mask |= (1 << bit); bit++; len--; } xoperands[0] = operands[0]; xoperands[1] = GEN_INT (trunc_int_for_mode (mask, SImode)); output_asm_insn (\"btst %1,%0\", xoperands); return \"\"; }" [(set_attr "cc" "clobber")]) (define_insn "" [(set (cc0) (zero_extract:SI (match_operand:QI 0 "general_operand" "R,dx") (match_operand 1 "const_int_operand" "") (match_operand 2 "const_int_operand" "")))] "mask_ok_for_mem_btst (INTVAL (operands[1]), INTVAL (operands[2]))" "* { int len = INTVAL (operands[1]); int bit = INTVAL (operands[2]); int mask = 0; rtx xoperands[2]; while (len > 0) { mask |= (1 << bit); bit++; len--; } /* If the source operand is not a reg (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) (and:SI (match_operand:SI 0 "register_operand" "dx") (match_operand:SI 1 "const_int_operand" "")))] "" "btst %1,%0" [(set_attr "cc" "clobber")]) (define_insn "" [(set (cc0) (and:SI (subreg:SI (match_operand:QI 0 "general_operand" "R,dx") 0) (match_operand:SI 1 "const_8bit_operand" "")))] "" "@ btst %U1,%A0 btst %1,%0" [(set_attr "cc" "clobber")]) ;; ---------------------------------------------------------------------- ;; 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.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); emit_move_insn (table, gen_rtx_LABEL_REF (VOIDmode, operands[3])); emit_move_insn (index, plus_constant (operands[0], - INTVAL (operands[1]))); emit_insn (gen_cmpsi (index, operands[2])); emit_jump_insn (gen_bgtu (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_insn (gen_rtx_USE (VOIDmode, 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_insn (gen_rtx_USE (VOIDmode, 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_no_conflict_block (insns, operands[0], operands[1], 0, 0); 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_no_conflict_block (insns, operands[0], operands[1], 0, 0); 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) (match_operand:SI 0 "register_operand" "dx")) (set (pc) (if_then_else (ge (cc0) (const_int 0)) (match_operand 1 "" "") (pc)))] "dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])" "add %0,%0\;bcc %1" [(set_attr "cc" "clobber")]) (define_peephole [(set (cc0) (match_operand:SI 0 "register_operand" "dx")) (set (pc) (if_then_else (lt (cc0) (const_int 0)) (match_operand 1 "" "") (pc)))] "dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])" "add %0,%0\;bcs %1" [(set_attr "cc" "clobber")]) (define_peephole [(set (cc0) (match_operand:SI 0 "register_operand" "dx")) (set (pc) (if_then_else (ge (cc0) (const_int 0)) (pc) (match_operand 1 "" "")))] "dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])" "add %0,%0\;bcs %1" [(set_attr "cc" "clobber")]) (define_peephole [(set (cc0) (match_operand:SI 0 "register_operand" "dx")) (set (pc) (if_then_else (lt (cc0) (const_int 0)) (pc) (match_operand 1 "" "")))] "dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])" "add %0,%0\;bcc %1" [(set_attr "cc" "clobber")]) (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 && current_function_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 (unspec [(minus:SI (match_dup 1) (const (minus:SI (const (match_operand:SI 0 "" "")) (pc)))) ] UNSPEC_PIC))))] "" " { operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME); }") (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)] "" "")