;; GCC machine description for Matsushita MN10300 ;; Copyright (C) 1996, 1997 Free Software Foundation, Inc.

;; Contributed by Jeff Law (law@cygnus.com).

;; This file is part of GNU CC.

;; GNU CC is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version.

;; GNU CC is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License ;; along with GNU CC; see the file COPYING. If not, write to ;; the Free Software Foundation, 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA.

;; The original PO technology requires these to be ordered by speed, ;; so that assigner will pick the fastest.

;; See file “rtl.def” for documentation on define_insn, match_*, et. al.

;; Condition code settings. ;; none - insn does not affect cc ;; none_0hit - insn does not affect cc but it does modify operand 0 ;; This attribute is used to keep track of when operand 0 changes. ;; See the description of NOTICE_UPDATE_CC for more info. ;; set_znv - insn sets z,n,v to usable values; c is unusable. ;; set_zn - insn sets z,n to usable values; v,c are unusable. ;; compare - compare instruction ;; invert -- like compare, but flags are inverted. ;; clobber - value of cc is unknown (define_attr “cc” “none,none_0hit,set_znv,set_zn,compare,clobber,invert” (const_string “clobber”)) ;; ---------------------------------------------------------------------- ;; MOVE INSTRUCTIONS ;; ----------------------------------------------------------------------

;; movqi

(define_expand “movqi” [(set (match_operand:QI 0 “general_operand” "") (match_operand:QI 1 “general_operand” "“))] "" " { /* One of the ops has to be in a register */ if (!register_operand (operand0, QImode) && !register_operand (operand1, QImode)) operands[1] = copy_to_mode_reg (QImode, operand1); }”)

(define_insn "" [(set (match_operand:QI 0 “general_operand” “=dx,*a,dx,*a,dx,*a,dx,*a,dx,m”) (match_operand:QI 1 “general_operand” “0,0,I,I,a,dx,dxi,ia,m,dx”))] “register_operand (operands[0], QImode) || register_operand (operands[1], QImode)” "* { switch (which_alternative) { case 0: case 1: return "nop"; case 2: return "clr %0"; case 3: case 4: case 5: case 6: case 7: 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 8:
case 9:
  return \"movbu %1,%0\";
}

}" [(set_attr “cc” “none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit”)])

;; movhi

(define_expand “movhi” [(set (match_operand:HI 0 “general_operand” "") (match_operand:HI 1 “general_operand” "“))] "" " { /* One of the ops has to be in a register */ if (!register_operand (operand1, HImode) && !register_operand (operand0, HImode)) operands[1] = copy_to_mode_reg (HImode, operand1); }”)

(define_insn "" [(set (match_operand:HI 0 “general_operand” “=dx,*a,dx,*a,dx,*a,dx,*a,dx,m”) (match_operand:HI 1 “general_operand” “0,0,I,I,a,dx,dxi,ia,m,dx”))] “register_operand (operands[0], HImode) || register_operand (operands[1], HImode)” “* { switch (which_alternative) { case 0: case 1: return "nop"; case 2: return "clr %0"; case 3: case 4: case 5: case 6: case 7: 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 8: case 9: return "movhu %1,%0"; } }” [(set_attr “cc” “none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit”)])

;; movsi and helpers

;; We use this to handle addition of two values when one operand is the ;; stack pointer and the other is a memory reference of some kind. Reload ;; does not handle them correctly without this expander. (define_expand “reload_insi” [(set (match_operand:SI 0 “register_operand” “=a”) (match_operand:SI 1 “impossible_plus_operand” "“)) (clobber (match_operand:SI 2 “register_operand” “=&r”))] "" " { if (XEXP (operands[1], 0) == stack_pointer_rtx) { 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_expand “movsi” [(set (match_operand:SI 0 “general_operand” "") (match_operand:SI 1 “general_operand” "“))] "" " { /* One of the ops has to be in a register */ if (!register_operand (operand1, SImode) && !register_operand (operand0, SImode)) operands[1] = copy_to_mode_reg (SImode, operand1); }”)

(define_insn "" [(set (match_operand:SI 0 “general_operand” “=dx,ax,dx,a,dxm,dxm,axm,axm,dx,dx,ax,ax,axR,y”) (match_operand:SI 1 “general_operand” “0,0,I,I,dx,ax,dx,ax,dixm,aixm,dixm,aixm,xy,axR”))] “register_operand (operands[0], SImode) || register_operand (operands[1], SImode)” “* { switch (which_alternative) { case 0: case 1: return "nop"; case 2: return "clr %0"; case 3: 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 ""; } return "mov %1,%0"; } }” [(set_attr “cc” “none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit”)])

(define_expand “movsf” [(set (match_operand:SF 0 “general_operand” "") (match_operand:SF 1 “general_operand” "“))] "" " { /* One of the ops has to be in a register */ if (!register_operand (operand1, SFmode) && !register_operand (operand0, SFmode)) operands[1] = copy_to_mode_reg (SFmode, operand1); }”)

(define_insn "" [(set (match_operand:SF 0 “general_operand” “=dx,ax,dx,a,daxm,dax”) (match_operand:SF 1 “general_operand” “0,0,G,G,dax,daxim”))] “register_operand (operands[0], SFmode) || register_operand (operands[1], SFmode)” “* { switch (which_alternative) { case 0: case 1: return "nop"; case 2: return "clr %0"; case 3: case 4: case 5: return "mov %1,%0"; } }” [(set_attr “cc” “none,none,clobber,none_0hit,none_0hit,none_0hit”)])

(define_expand “movdi” [(set (match_operand:DI 0 “general_operand” "") (match_operand:DI 1 “general_operand” "“))] "" " { /* One of the ops has to be in a register */ if (!register_operand (operand1, DImode) && !register_operand (operand0, DImode)) operands[1] = copy_to_mode_reg (DImode, operand1); }”)

(define_insn "" [(set (match_operand:DI 0 “general_operand” “=dx,ax,dx,a,dxm,dxm,axm,axm,dx,dx,ax,ax”) (match_operand:DI 1 “general_operand” “0,0,I,I,dx,ax,dx,ax,dxim,axim,dxim,axim”))] “register_operand (operands[0], DImode) || register_operand (operands[1], DImode)” "* { long val[2]; REAL_VALUE_TYPE rv;

switch (which_alternative) { case 0: case 1: return "nop";

  case 2:
return \"clr %L0\;clr %H0\";

  case 3:
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)
  {
    val[0] = INTVAL (operands[1]);
    val[1] = val[0] < 0 ? -1 : 0;
  }
if (GET_CODE (operands[1]) == CONST_DOUBLE)
  {
    if (GET_MODE (operands[1]) == DFmode)
      {
	REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
	REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
      }
    else if (GET_MODE (operands[1]) == VOIDmode
	     || GET_MODE (operands[1]) == DImode)
      {
	val[0] = CONST_DOUBLE_LOW (operands[1]);
	val[1] = CONST_DOUBLE_HIGH (operands[1]);
      }
  }

if (GET_CODE (operands[1]) == MEM
    && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0)))
  {
    rtx temp = operands[0];

    while (GET_CODE (temp) == SUBREG)
      temp = SUBREG_REG (temp);

    if (GET_CODE (temp) != REG)
      abort ();

    if (reg_overlap_mentioned_p (gen_rtx (REG, SImode, REGNO (temp)),
				 XEXP (operands[1], 0)))
      return \"mov %H1,%H0\;mov %L1,%L0\";
    else
      return \"mov %L1,%L0\;mov %H1,%H0\";
      
  }
else if (GET_CODE (operands[1]) == MEM
	 && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))
	 && REGNO_REG_CLASS (REGNO (operands[0])) == ADDRESS_REGS)
  {
    rtx xoperands[2];

    xoperands[0] = operands[0];
    xoperands[1] = XEXP (operands[1], 0);

    output_asm_insn (\"mov %1,%L0\;mov (4,%L0),%H0\;mov (%L0),%L0\",
		     xoperands);
    return \"\";
  }
else
  {
    if ((GET_CODE (operands[1]) == CONST_INT
	 || GET_CODE (operands[1]) == CONST_DOUBLE)
	&& val[0] == 0)
      {
	if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
	  output_asm_insn (\"clr %L0\", operands);
	else
	  output_asm_insn (\"mov %L1,%L0\", operands);
      }
    else
      output_asm_insn (\"mov %L1,%L0\", operands);

    if ((GET_CODE (operands[1]) == CONST_INT
	 || GET_CODE (operands[1]) == CONST_DOUBLE)
	&& val[1] == 0)
      {
	if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
	  output_asm_insn (\"clr %H0\", operands);
	else
	  output_asm_insn (\"mov %H1,%H0\", operands);
      }
    else if ((GET_CODE (operands[1]) == CONST_INT
	      || GET_CODE (operands[1]) == CONST_DOUBLE)
	     && val[0] == val[1])
      output_asm_insn (\"mov %L0,%H0\", operands);
    else
      output_asm_insn (\"mov %H1,%H0\", operands);
    return \"\";
  }
}

}" [(set_attr “cc” “none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit”)])

(define_expand “movdf” [(set (match_operand:DF 0 “general_operand” "") (match_operand:DF 1 “general_operand” "“))] "" " { /* One of the ops has to be in a register */ if (!register_operand (operand1, DFmode) && !register_operand (operand0, DFmode)) operands[1] = copy_to_mode_reg (DFmode, operand1); }”)

(define_insn "" [(set (match_operand:DF 0 “general_operand” “=dx,ax,dx,a,dxm,dxm,axm,axm,dx,dx,ax,ax”) (match_operand:DF 1 “general_operand” “0,0,G,G,dx,ax,dx,ax,dxim,axim,dxim,axim”))] “register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode)” "* { long val[2]; REAL_VALUE_TYPE rv;

switch (which_alternative) { case 0: case 1: return "nop";

  case 2:
return \"clr %L0\;clr %H0\";

  case 3:
 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)
  {
    val[0] = INTVAL (operands[1]);
    val[1] = val[0] < 0 ? -1 : 0;
  }
if (GET_CODE (operands[1]) == CONST_DOUBLE)
  {
    if (GET_MODE (operands[1]) == DFmode)
      {
	REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
	REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
      }
    else if (GET_MODE (operands[1]) == VOIDmode
	     || GET_MODE (operands[1]) == DImode)
      {
	val[0] = CONST_DOUBLE_LOW (operands[1]);
	val[1] = CONST_DOUBLE_HIGH (operands[1]);
      }
  }

if (GET_CODE (operands[1]) == MEM
    && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0)))
  {
    rtx temp = operands[0];

    while (GET_CODE (temp) == SUBREG)
      temp = SUBREG_REG (temp);

    if (GET_CODE (temp) != REG)
      abort ();

    if (reg_overlap_mentioned_p (gen_rtx (REG, SImode, REGNO (temp)),
				 XEXP (operands[1], 0)))
      return \"mov %H1,%H0\;mov %L1,%L0\";
    else
      return \"mov %L1,%L0\;mov %H1,%H0\";
      
  }
else if (GET_CODE (operands[1]) == MEM
	 && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))
	 && REGNO_REG_CLASS (REGNO (operands[0])) == ADDRESS_REGS)
  {
    rtx xoperands[2];

    xoperands[0] = operands[0];
    xoperands[1] = XEXP (operands[1], 0);

    output_asm_insn (\"mov %1,%L0\;mov (4,%L0),%H0\;mov (%L0),%L0\",
		     xoperands);
    return \"\";
  }
else
  {
    if ((GET_CODE (operands[1]) == CONST_INT
	 || GET_CODE (operands[1]) == CONST_DOUBLE)
	&& val[0] == 0)
      {
	if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
	  output_asm_insn (\"clr %L0\", operands);
	else
	  output_asm_insn (\"mov %L1,%L0\", operands);
      }
    else
      output_asm_insn (\"mov %L1,%L0\", operands);

    if ((GET_CODE (operands[1]) == CONST_INT
	 || GET_CODE (operands[1]) == CONST_DOUBLE)
	&& val[1] == 0)
      {
	if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
	  output_asm_insn (\"clr %H0\", operands);
	else
	  output_asm_insn (\"mov %H1,%H0\", operands);
      }
    else if ((GET_CODE (operands[1]) == CONST_INT
	      || GET_CODE (operands[1]) == CONST_DOUBLE)
	     && val[0] == val[1])
      output_asm_insn (\"mov %L0,%H0\", operands);
    else
      output_asm_insn (\"mov %H1,%H0\", operands);
    return \"\";
  }
}

}" [(set_attr “cc” “none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit”)])

;; ---------------------------------------------------------------------- ;; TEST INSTRUCTIONS ;; ----------------------------------------------------------------------

;; Go ahead and define tstsi so we can eliminate redundant tst insns ;; when we start trying to optimize this port. (define_insn “tstsi” [(set (cc0) (match_operand:SI 0 “register_operand” “dax”))] "" “* return output_tst (operands[0], insn);” [(set_attr “cc” “set_znv”)])

(define_insn "" [(set (cc0) (zero_extend:SI (match_operand:QI 0 “memory_operand” “dx”)))] "" “* return output_tst (operands[0], insn);” [(set_attr “cc” “set_znv”)])

(define_insn "" [(set (cc0) (zero_extend:SI (match_operand:HI 0 “memory_operand” “dx”)))] "" “* return output_tst (operands[0], insn);” [(set_attr “cc” “set_znv”)])

(define_insn “cmpsi” [(set (cc0) (compare (match_operand:SI 0 “register_operand” “!da*x,dax”) (match_operand:SI 1 “nonmemory_operand” “!*0,daxi”)))] "" “@ add 0,%0 cmp %1,%0” [(set_attr “cc” “invert,compare”)]) ;; ---------------------------------------------------------------------- ;; ADD INSTRUCTIONS ;; ----------------------------------------------------------------------

(define_expand “addsi3” [(set (match_operand:SI 0 “register_operand” "") (plus:SI (match_operand:SI 1 “register_operand” "") (match_operand:SI 2 “nonmemory_operand” "“)))] "" " { /* We can't add a variable amount directly to the stack pointer; so do so via a temporary register. */ if (operands[0] == stack_pointer_rtx && GET_CODE (operands[1]) != CONST_INT && GET_CODE (operands[2]) != CONST_INT) { rtx temp = gen_reg_rtx (SImode); emit_move_insn (temp, gen_rtx (PLUS, SImode, operands[1], operands[2])); emit_move_insn (operands[0], temp); DONE; } }”)

(define_insn "" [(set (match_operand:SI 0 “register_operand” “=dx,ax,ax,dax,xy,!dax”) (plus:SI (match_operand:SI 1 “register_operand” “%0,0,0,0,0,dax”) (match_operand:SI 2 “nonmemory_operand” “J,J,L,daxi,i,dax”)))] "" "* { switch (which_alternative) { case 0: case 1: return "inc %0"; case 2: return "inc4 %0"; case 3: case 4: return "add %2,%0"; case 5: /* I'm not sure if this can happen or not. Might as well be prepared and generate the best possible code if it does happen. */ if (true_regnum (operands[0]) == true_regnum (operands[1])) return "add %2,%0"; if (true_regnum (operands[0]) == true_regnum (operands[2])) return "add %1,%0";

  /* We have to copy one of the sources into the destination, then add
 the other source to the destination.

 Carefully select which source to copy to the destination; a naive
 implementation will waste a byte when the source classes are different
 and the destination is an address register.  Selecting the lowest
 cost register copy will optimize this sequence.  */
  if (REGNO_REG_CLASS (true_regnum (operands[1]))
  == REGNO_REG_CLASS (true_regnum (operands[0])))
return \"mov %1,%0\;add %2,%0\";
  return \"mov %2,%0\;add %1,%0\";
}

}" [(set_attr “cc” “set_zn,none_0hit,none_0hit,set_zn,none_0hit,set_zn”)])

;; ---------------------------------------------------------------------- ;; SUBTRACT INSTRUCTIONS ;; ----------------------------------------------------------------------

(define_expand “subsi3” [(set (match_operand:SI 0 “register_operand” "") (minus:SI (match_operand:SI 1 “register_operand” "") (match_operand:SI 2 “nonmemory_operand” "")))] "" "")

(define_insn "" [(set (match_operand:SI 0 “register_operand” “=dax”) (minus:SI (match_operand:SI 1 “register_operand” “0”) (match_operand:SI 2 “nonmemory_operand” “daxi”)))] "" “sub %2,%0” [(set_attr “cc” “set_zn”)])

(define_expand “negsi2” [(set (match_operand:SI 0 “register_operand” "") (neg:SI (match_operand:SI 1 “register_operand” "")))] "" " { rtx target = gen_reg_rtx (SImode);

emit_move_insn (target, GEN_INT (0)); emit_insn (gen_subsi3 (target, target, operands[1])); emit_move_insn (operands[0], target); DONE; }")

;; ---------------------------------------------------------------------- ;; MULTIPLY INSTRUCTIONS ;; ----------------------------------------------------------------------

(define_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”) (mult:SI (match_operand:SI 1 “register_operand” “%0”) (match_operand:SI 2 “register_operand” “dx”)))] "" “* { if (TARGET_MULT_BUG) return "nop;nop;mul %2,%0"; else return "mul %2,%0"; }” [(set_attr “cc” “set_zn”)])

(define_insn “udivmodsi4” [(set (match_operand:SI 0 “general_operand” “=dx”) (udiv:SI (match_operand:SI 1 “general_operand” “0”) (match_operand:SI 2 “general_operand” “dx”))) (set (match_operand:SI 3 “general_operand” “=&d”) (umod:SI (match_dup 1) (match_dup 2)))] "" "* { output_asm_insn ("sub %3,%3;mov %3,mdr", operands);

if (find_reg_note (insn, REG_UNUSED, operands[3])) return "divu %2,%0"; else return "divu %2,%0;mov mdr,%3"; }" [(set_attr “cc” “set_zn”)])

(define_insn “divmodsi4” [(set (match_operand:SI 0 “general_operand” “=dx”) (div:SI (match_operand:SI 1 “general_operand” “0”) (match_operand:SI 2 “general_operand” “dx”))) (set (match_operand:SI 3 “general_operand” “=d”) (mod:SI (match_dup 1) (match_dup 2)))] "" “* { if (find_reg_note (insn, REG_UNUSED, operands[3])) return "ext %0;div %2,%0"; else return "ext %0;div %2,%0;mov mdr,%3"; }” [(set_attr “cc” “set_zn”)])

;; ---------------------------------------------------------------------- ;; AND INSTRUCTIONS ;; ----------------------------------------------------------------------

(define_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”) (and:SI (match_operand:SI 1 “register_operand” “%0,0”) (match_operand:SI 2 “nonmemory_operand” “N,dxi”)))] "" “* { if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xff) return "extbu %0"; if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xffff) return "exthu %0"; if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x7fffffff) return "add %0,%0;lsr 1,%0"; if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x3fffffff) return "asl2 %0;lsr 2,%0"; if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x1fffffff) return "add %0,%0;asl2 %0;lsr 3,%0"; if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x0fffffff) return "asl2 %0;asl2 %0;lsr 4,%0"; if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffffe) return "lsr 1,%0;add %0,%0"; if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffffc) return "lsr 2,%0;asl2 %0"; if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffff8) return "lsr 3,%0;add %0,%0;asl2 %0"; if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffff0) return "lsr 4,%0;asl2 %0;asl2 %0"; return "and %2,%0"; }” [(set_attr “cc” “none_0hit,set_znv”)])

;; ---------------------------------------------------------------------- ;; OR INSTRUCTIONS ;; ----------------------------------------------------------------------

(define_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”) (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”) (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”) (not:SI (match_operand:SI 1 “register_operand” “0”)))] "" “not %0” [(set_attr “cc” “set_znv”)]) ;; ----------------------------------------------------------------- ;; BIT FIELDS ;; -----------------------------------------------------------------

;; These set/clear memory in byte sized chunks. ;; ;; They are no smaller/faster than loading the value into a register ;; and storing the register, but they don't need a scratch register ;; which may allow for better code generation. (define_insn "" [(set (match_operand:QI 0 “general_operand” “=R,d”) (const_int 0))] "" “@ bclr 255,%A0 clr %0” [(set_attr “cc” “clobber”)])

(define_insn "" [(set (match_operand:QI 0 “general_operand” “=R,d”) (const_int -1))] "" “@ bset 255,%A0 mov -1,%0” [(set_attr “cc” “clobber,none_0hit”)])

(define_insn "" [(set (match_operand:QI 0 “general_operand” “+R,d”) (subreg:QI (and:SI (subreg:SI (match_dup 0) 0) (match_operand:SI 1 “const_int_operand” “i,i”)) 0))] "" “@ bclr %N1,%A0 and %1,%0” [(set_attr “cc” “clobber,set_znv”)])

(define_insn "" [(set (match_operand:QI 0 “general_operand” “+R,d”) (subreg:QI (ior:SI (subreg:SI (match_dup 0) 0) (match_operand:SI 1 “const_int_operand” “i,i”)) 0))] "" “@ bset %1,%A0 or %1,%0” [(set_attr “cc” “clobber,set_znv”)])

(define_insn "" [(set (cc0) (zero_extract:SI (match_operand:SI 0 “register_operand” “dx”) (match_operand 1 “const_int_operand” "") (match_operand 2 “const_int_operand” "")))] "" "* { int len = INTVAL (operands[1]); int bit = INTVAL (operands[2]); int mask = 0; rtx xoperands[2];

while (len > 0) { mask |= (1 << bit); bit++; len--; }

xoperands[0] = operands[0]; xoperands[1] = GEN_INT (mask); output_asm_insn ("btst %1,%0", xoperands); return ""; }" [(set_attr “cc” “set_znv”)])

(define_insn "" [(set (cc0) (zero_extract:SI (match_operand:QI 0 “general_operand” “R,dx”) (match_operand 1 “const_int_operand” "") (match_operand 2 “const_int_operand” "")))] “mask_ok_for_mem_btst (INTVAL (operands[1]), INTVAL (operands[2]))” "* { int len = INTVAL (operands[1]); int bit = INTVAL (operands[2]); int mask = 0; rtx xoperands[2];

while (len > 0) { mask |= (1 << bit); bit++; len--; }

/* If the source operand is not a reg (ie it is memory), then extract the bits from mask that we actually want to test. Note that the mask will never cross a byte boundary. */ if (!REG_P (operands[0])) { if (mask & 0xff) mask = mask & 0xff; else if (mask & 0xff00) mask = (mask >> 8) & 0xff; else if (mask & 0xff0000) mask = (mask >> 16) & 0xff; else if (mask & 0xff000000) mask = (mask >> 24) & 0xff; }

xoperands[0] = operands[0]; xoperands[1] = GEN_INT (mask); if (GET_CODE (operands[0]) == REG) output_asm_insn ("btst %1,%0", xoperands); else output_asm_insn ("btst %1,%A0", xoperands); return ""; }" [(set_attr “cc” “set_znv”)])

(define_insn "" [(set (cc0) (and:SI (match_operand:SI 0 “register_operand” “dx”) (match_operand:SI 1 “const_int_operand” "")))] "" “btst %1,%0” [(set_attr “cc” “set_znv”)])

(define_insn "" [(set (cc0) (and:SI (subreg:SI (match_operand:QI 0 “general_operand” “R,dx”) 0) (match_operand:SI 1 “const_8bit_operand” "")))] "" “@ btst %1,%A0 btst %1,%0” [(set_attr “cc” “set_znv”)])

;; ---------------------------------------------------------------------- ;; JUMP INSTRUCTIONS ;; ----------------------------------------------------------------------

;; Conditional jump instructions

(define_expand “ble” [(set (pc) (if_then_else (le (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "")

(define_expand “bleu” [(set (pc) (if_then_else (leu (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "")

(define_expand “bge” [(set (pc) (if_then_else (ge (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "")

(define_expand “bgeu” [(set (pc) (if_then_else (geu (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "")

(define_expand “blt” [(set (pc) (if_then_else (lt (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "")

(define_expand “bltu” [(set (pc) (if_then_else (ltu (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "")

(define_expand “bgt” [(set (pc) (if_then_else (gt (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "")

(define_expand “bgtu” [(set (pc) (if_then_else (gtu (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "")

(define_expand “beq” [(set (pc) (if_then_else (eq (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "")

(define_expand “bne” [(set (pc) (if_then_else (ne (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "")

(define_insn "" [(set (pc) (if_then_else (match_operator 1 “comparison_operator” [(cc0) (const_int 0)]) (label_ref (match_operand 0 "" "")) (pc)))] "" “* { if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0 && (GET_CODE (operands[1]) == GT || GET_CODE (operands[1]) == GE || GET_CODE (operands[1]) == LE || GET_CODE (operands[1]) == LT)) return 0; return "b%b1 %0"; }” [(set_attr “cc” “none”)])

(define_insn "" [(set (pc) (if_then_else (match_operator 1 “comparison_operator” [(cc0) (const_int 0)]) (pc) (label_ref (match_operand 0 "" ""))))] "" “* { if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0 && (GET_CODE (operands[1]) == GT || GET_CODE (operands[1]) == GE || GET_CODE (operands[1]) == LE || GET_CODE (operands[1]) == LT)) return 0; return "b%B1 %0"; }” [(set_attr “cc” “none”)])

;; Unconditional and other jump instructions.

(define_insn “jump” [(set (pc) (label_ref (match_operand 0 "" "")))] "" “jmp %l0” [(set_attr “cc” “none”)])

(define_insn “indirect_jump” [(set (pc) (match_operand:SI 0 “register_operand” “a”))] "" “jmp (%0)” [(set_attr “cc” “none”)])

(define_insn “tablejump” [(set (pc) (match_operand:SI 0 “register_operand” “a”)) (use (label_ref (match_operand 1 "" "")))] "" “jmp (%0)” [(set_attr “cc” “none”)])

;; Call subroutine with no return value.

(define_expand “call” [(call (match_operand:QI 0 “general_operand” "") (match_operand:SI 1 “general_operand” "“))] "" " { if (! call_address_operand (XEXP (operands[0], 0))) XEXP (operands[0], 0) = force_reg (SImode, XEXP (operands[0], 0)); emit_call_insn (gen_call_internal (XEXP (operands[0], 0), operands[1])); DONE; }”)

(define_insn “call_internal” [(call (mem:QI (match_operand:SI 0 “call_address_operand” “aS”)) (match_operand:SI 1 “general_operand” “g”))] "" “* { if (REG_P (operands[0])) return "calls %C0"; else return "call %C0,[],0"; }” [(set_attr “cc” “clobber”)])

;; Call subroutine, returning value in operand 0 ;; (which must be a hard register).

(define_expand “call_value” [(set (match_operand 0 "" "") (call (match_operand:QI 1 “general_operand” "") (match_operand:SI 2 “general_operand” "“)))] "" " { if (! call_address_operand (XEXP (operands[1], 0))) XEXP (operands[1], 0) = force_reg (SImode, XEXP (operands[1], 0)); emit_call_insn (gen_call_value_internal (operands[0], XEXP (operands[1], 0), operands[2])); DONE; }”)

(define_insn “call_value_internal” [(set (match_operand 0 "" “=dax”) (call (mem:QI (match_operand:SI 1 “call_address_operand” “aS”)) (match_operand:SI 2 “general_operand” “g”)))] "" “* { if (REG_P (operands[1])) return "calls %C1"; else return "call %C1,[],0"; }” [(set_attr “cc” “clobber”)])

(define_expand “untyped_call” [(parallel [(call (match_operand 0 "" "") (const_int 0)) (match_operand 1 "" "") (match_operand 2 "" "")])] "" " { int i;

emit_call_insn (gen_call (operands[0], const0_rtx));

for (i = 0; i < XVECLEN (operands[2], 0); i++) { rtx set = XVECEXP (operands[2], 0, i); emit_move_insn (SET_DEST (set), SET_SRC (set)); } DONE; }")

(define_insn “nop” [(const_int 0)] "" “nop” [(set_attr “cc” “none”)]) ;; ---------------------------------------------------------------------- ;; EXTEND INSTRUCTIONS ;; ----------------------------------------------------------------------

(define_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 “general_operand” “=dx,dx,dx”) (zero_extend:SI (match_operand:QI 1 “general_operand” “0,d,m”)))] "" “@ extbu %0 mov %1,%0;extbu %0 movbu %1,%0” [(set_attr “cc” “none_0hit”)])

(define_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 “general_operand” “=dx,dx,dx”) (zero_extend:SI (match_operand:HI 1 “general_operand” “0,dx,m”)))] "" “@ exthu %0 mov %1,%0;exthu %0 movhu %1,%0” [(set_attr “cc” “none_0hit”)])

;;- sign extension instructions

(define_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 “general_operand” “=dx,dx”) (sign_extend:SI (match_operand:QI 1 “general_operand” “0,dx”)))] "" “@ extb %0 mov %1,%0;extb %0” [(set_attr “cc” “none_0hit”)])

(define_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 “general_operand” “=dx,dx”) (sign_extend:SI (match_operand:HI 1 “general_operand” “0,dx”)))] "" “@ exth %0 mov %1,%0;exth %0” [(set_attr “cc” “none_0hit”)]) ;; ---------------------------------------------------------------------- ;; SHIFTS ;; ----------------------------------------------------------------------

(define_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,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”) (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”) (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);

if (result == 0) abort ();

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;

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); if (result == 0) abort ();

if (result != target) emit_move_insn (result, target);

/* Make a place for REG_EQUAL. */ emit_move_insn (operands[0], operands[0]); DONE; }")

(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(0x80000000), target, 0, OPTAB_WIDEN);

if (result == 0) abort ();

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;

target = operand_subword_force (operands[0], 0, SFmode); result = expand_binop (SImode, xor_optab, operand_subword_force (operands[1], 0, SFmode), GEN_INT(0x80000000), target, 0, OPTAB_WIDEN); if (result == 0) abort ();

if (result != target) emit_move_insn (result, target);

/* Make a place for REG_EQUAL. */ emit_move_insn (operands[0], operands[0]); DONE; }")

;; ---------------------------------------------------------------------- ;; PROLOGUE/EPILOGUE ;; ---------------------------------------------------------------------- (define_expand “prologue” [(const_int 0)] "" “expand_prologue (); DONE;”)

(define_expand “epilogue” [(return)] "" " { expand_epilogue (); DONE; }")

(define_insn “return_internal” [(const_int 2)] "" “rets” [(set_attr “cc” “clobber”)])

;; This insn restores the callee saved registers and does a return, it ;; can also deallocate stack space. (define_insn “return_internal_regs” [(const_int 0) (match_operand:SI 0 “const_int_operand” “i”) (return)] "" "* { int i, need_comma; int d2, d3, a2, a3;

need_comma = 0; fputs ("\tret [", asm_out_file); if (regs_ever_live[2]) { fputs ("d2", asm_out_file); need_comma = 1; } if (regs_ever_live[3]) { if (need_comma) fputc (‘,’, asm_out_file); fputs ("d3", asm_out_file); need_comma = 1; } if (regs_ever_live[6]) { if (need_comma) fputc (‘,’, asm_out_file); fputs ("a2", asm_out_file); need_comma = 1; } if (regs_ever_live[7]) { if (need_comma) fputc (‘,’, asm_out_file); fputs ("a3", asm_out_file); need_comma = 1; } fprintf (asm_out_file, "],%d\n", INTVAL (operands[0])); return ""; }" [(set_attr “cc” “clobber”)])

(define_insn “store_movm” [(const_int 1)] "" "* { int i, need_comma; int d2, d3, a2, a3;

need_comma = 0; fputs ("\tmovm [", asm_out_file); if (regs_ever_live[2]) { fputs ("d2", asm_out_file); need_comma = 1; } if (regs_ever_live[3]) { if (need_comma) fputc (‘,’, asm_out_file); fputs ("d3", asm_out_file); need_comma = 1; } if (regs_ever_live[6]) { if (need_comma) fputc (‘,’, asm_out_file); fputs ("a2", asm_out_file); need_comma = 1; } if (regs_ever_live[7]) { if (need_comma) fputc (‘,’, asm_out_file); fputs ("a3", asm_out_file); need_comma = 1; } fputs ("],(sp)\n", asm_out_file); 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”)])