gcc-papermario/config/mn10300/mn10300.md
2020-09-20 21:06:00 -04:00

36 KiB
Raw Permalink Blame History

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

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

;; This file is part of GNU CC.

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

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

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

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

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

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

;; movqi

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

(define_insn "" [(set (match_operand:QI 0 "general_operand" "=d,*a,d,*a,d,*a,d,a,d,m") (match_operand:QI 1 "general_operand" "0,0,I,I,a,d,di,ia,m,d"))] "register_operand (operands[0], QImode) || register_operand (operands[1], QImode)" " { switch (which_alternative) { case 0: case 1: return "nop"; case 2: return "clr %0"; case 3: if (zero_areg) { rtx xoperands[2];

  xoperands[0] = operands[0];
  xoperands[1] = zero_areg;
  if (rtx_equal_p (xoperands[0], xoperands[1]))
    output_asm_insn (\"sub %1,%0\", xoperands);
  else
    output_asm_insn (\"mov %1,%0\", xoperands);
  return \"\";
}

  /* FALLTHROUGH */
case 4:
case 5:
case 6:
case 7:
  return \"mov %1,%0\";
case 8:
case 9:
  return \"movbu %1,%0\";
}

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

;; movhi

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

(define_insn "" [(set (match_operand:HI 0 "general_operand" "=d,*a,d,*a,d,*a,d,a,d,m") (match_operand:HI 1 "general_operand" "0,0,I,I,a,d,di,ia,m,d"))] "register_operand (operands[0], HImode) || register_operand (operands[1], HImode)" " { switch (which_alternative) { case 0: case 1: return "nop"; case 2: return "clr %0"; case 3: if (zero_areg) { rtx xoperands[2];

  xoperands[0] = operands[0];
  xoperands[1] = zero_areg;
  if (rtx_equal_p (xoperands[0], xoperands[1]))
    output_asm_insn (\"sub %1,%0\", xoperands);
  else
    output_asm_insn (\"mov %1,%0\", xoperands);
  return \"\";
}

  /* FALLTHROUGH */
case 4:
case 5:
case 6:
case 7:
  return \"mov %1,%0\";
case 8:
case 9:
  return \"movhu %1,%0\";
}

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

;; movsi and helpers

;; We use this to handle addition of two values when one operand is the ;; stack pointer and the other is a memory reference of some kind. Reload ;; does not handle them correctly without this expander. (define_expand "reload_insi" [(set (match_operand:SI 0 "register_operand" "=a") (match_operand:SI 1 "impossible_plus_operand" "")) (clobber (match_operand:SI 2 "register_operand" "=&r"))] "" " { if (XEXP (operands[1], 0) == stack_pointer_rtx) { emit_move_insn (operands[0], XEXP (operands[1], 0)); if (GET_CODE (XEXP (operands[1], 1)) == SUBREG && (GET_MODE_SIZE (GET_MODE (XEXP (operands[1], 1))) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (operands[1], 1)))))) emit_move_insn (operands[2], gen_rtx (ZERO_EXTEND, GET_MODE (XEXP (operands[1], 1)), SUBREG_REG (XEXP (operands[1], 1)))); else emit_move_insn (operands[2], XEXP (operands[1], 1)); } else { emit_move_insn (operands[0], XEXP (operands[1], 1)); if (GET_CODE (XEXP (operands[1], 0)) == SUBREG && (GET_MODE_SIZE (GET_MODE (XEXP (operands[1], 0))) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (operands[1], 0)))))) emit_move_insn (operands[2], gen_rtx (ZERO_EXTEND, GET_MODE (XEXP (operands[1], 0)), SUBREG_REG (XEXP (operands[1], 0)))); else emit_move_insn (operands[2], XEXP (operands[1], 0)); } emit_insn (gen_addsi3 (operands[0], operands[0], operands[2])); DONE; }")

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

(define_insn "" [(set (match_operand:SI 0 "general_operand" "=d,a,d,a,dm,dm,am,am,d,d,a,a,aR,x") (match_operand:SI 1 "general_operand" "0,0,I,I,d,a,d,a,dim,aim,dim,aim,x,aR"))] "register_operand (operands[0], SImode) || register_operand (operands[1], SImode)" "* { switch (which_alternative) { case 0: case 1: return "nop"; case 2: return "clr %0"; case 3: if (zero_areg) { rtx xoperands[2];

  xoperands[0] = operands[0];
  xoperands[1] = zero_areg;
  if (rtx_equal_p (xoperands[0], xoperands[1]))
    output_asm_insn (\"sub %1,%0\", xoperands);
  else
    output_asm_insn (\"mov %1,%0\", xoperands);
  return \"\";
}

  /* FALLTHROUGH */
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
  return \"mov %1,%0\";
}

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

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

(define_insn "" [(set (match_operand:SF 0 "general_operand" "=d,a,d,a,dam,da") (match_operand:SF 1 "general_operand" "0,0,G,G,da,daim"))] "register_operand (operands[0], SFmode) || register_operand (operands[1], SFmode)" "* { switch (which_alternative) { case 0: case 1: return "nop"; case 2: return "clr %0"; case 3: if (zero_areg) { rtx xoperands[2];

  xoperands[0] = operands[0];
  xoperands[1] = zero_areg;
  if (rtx_equal_p (xoperands[0], xoperands[1]))
    output_asm_insn (\"sub %1,%0\", xoperands);
  else
    output_asm_insn (\"mov %1,%0\", xoperands);
  return \"\";
}

  /* FALLTHROUGH */
case 4:
case 5:
  return \"mov %1,%0\";
}

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

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

(define_insn "" [(set (match_operand:DI 0 "general_operand" "=d,a,d,a,dm,dm,am,am,d,d,a,a") (match_operand:DI 1 "general_operand" "0,0,I,I,d,a,d,a,dim,aim,dim,aim"))] "register_operand (operands[0], DImode) || register_operand (operands[1], DImode)" "* { long val[2]; REAL_VALUE_TYPE rv;

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

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

  case 3:
  {
    rtx xoperands[2];

    xoperands[0] = operands[0];
    xoperands[1] = zero_areg ? zero_areg : operands[1];
    if (rtx_equal_p (xoperands[0], xoperands[1]))
      output_asm_insn (\"sub %L1,%L0\;mov %L0,%H0\", xoperands);
    else
      output_asm_insn (\"mov %1,%L0\;mov %L0,%H0\", xoperands);
    return \"\";
  }
  case 4:
  case 5:
  case 6:
  case 7:
  case 8:
  case 9:
  case 10:
  case 11:
if (GET_CODE (operands[1]) == CONST_INT)
  {
    val[0] = INTVAL (operands[1]);
    val[1] = val[0] < 0 ? -1 : 0;
  }
if (GET_CODE (operands[1]) == CONST_DOUBLE)
  {
    if (GET_MODE (operands[1]) == DFmode)
      {
	REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
	REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
      }
    else if (GET_MODE (operands[1]) == VOIDmode
	     || GET_MODE (operands[1]) == DImode)
      {
	val[0] = CONST_DOUBLE_LOW (operands[1]);
	val[1] = CONST_DOUBLE_HIGH (operands[1]);
      }
  }

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

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

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

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

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

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

	    xoperands[0] = operands[0];
	    xoperands[1] = zero_areg;
	    if (rtx_equal_p (xoperands[0], xoperands[1]))
	      output_asm_insn (\"sub %L0,%L0\", xoperands);
	    else
	      output_asm_insn (\"mov %1,%L0\", xoperands);
	  }
	else
	  output_asm_insn (\"mov %L1,%L0\", operands);
      }
    else
      output_asm_insn (\"mov %L1,%L0\", operands);

    if ((GET_CODE (operands[1]) == CONST_INT
	 || GET_CODE (operands[1]) == CONST_DOUBLE)
	&& val[1] == 0)
      {
	if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
	  output_asm_insn (\"clr %H0\", operands);
	else if (zero_areg)
	  {
	    rtx xoperands[2];

	    xoperands[0] = operands[0];
	    xoperands[1] = zero_areg;
	    if (rtx_equal_p (xoperands[0], xoperands[1]))
	      output_asm_insn (\"sub %H0,%H0\", xoperands);
	    else
	      output_asm_insn (\"mov %1,%H0\", xoperands);
	  }
	else
	  output_asm_insn (\"mov %H1,%H0\", operands);
      }
    else if ((GET_CODE (operands[1]) == CONST_INT
	      || GET_CODE (operands[1]) == CONST_DOUBLE)
	     && val[0] == val[1])
      output_asm_insn (\"mov %L0,%H0\", operands);
    else
      output_asm_insn (\"mov %H1,%H0\", operands);
    return \"\";
  }
}

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

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

(define_insn "" [(set (match_operand:DF 0 "general_operand" "=d,a,d,a,dm,dm,am,am,d,d,a,a") (match_operand:DF 1 "general_operand" "0,0,G,G,d,a,d,a,dim,aim,dim,aim"))] "register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode)" "* { long val[2]; REAL_VALUE_TYPE rv;

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

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

  case 3:
  {
    rtx xoperands[2];

    xoperands[0] = operands[0];
    xoperands[1] = zero_areg ? zero_areg : operands[1];
    if (rtx_equal_p (xoperands[0], xoperands[1]))
      output_asm_insn (\"sub %L1,%L0\;mov %L0,%H0\", xoperands);
    else
      output_asm_insn (\"mov %1,%L0\;mov %L0,%H0\", xoperands);
    return \"\";
  }
  case 4:
  case 5:
  case 6:
  case 7:
  case 8:
  case 9:
  case 10:
  case 11:
if (GET_CODE (operands[1]) == CONST_INT)
  {
    val[0] = INTVAL (operands[1]);
    val[1] = val[0] < 0 ? -1 : 0;
  }
if (GET_CODE (operands[1]) == CONST_DOUBLE)
  {
    if (GET_MODE (operands[1]) == DFmode)
      {
	REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
	REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
      }
    else if (GET_MODE (operands[1]) == VOIDmode
	     || GET_MODE (operands[1]) == DImode)
      {
	val[0] = CONST_DOUBLE_LOW (operands[1]);
	val[1] = CONST_DOUBLE_HIGH (operands[1]);
      }
  }

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

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

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

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

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

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

	    xoperands[0] = operands[0];
	    xoperands[1] = zero_areg;
	    if (rtx_equal_p (xoperands[0], xoperands[1]))
	      output_asm_insn (\"sub %L0,%L0\", xoperands);
	    else
	      output_asm_insn (\"mov %1,%L0\", xoperands);
	  }
	else
	  output_asm_insn (\"mov %L1,%L0\", operands);
      }
    else
      output_asm_insn (\"mov %L1,%L0\", operands);

    if ((GET_CODE (operands[1]) == CONST_INT
	 || GET_CODE (operands[1]) == CONST_DOUBLE)
	&& val[1] == 0)
      {
	if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
	  output_asm_insn (\"clr %H0\", operands);
	else if (zero_areg)
	  {
	    rtx xoperands[2];

	    xoperands[0] = operands[0];
	    xoperands[1] = zero_areg;
	    if (rtx_equal_p (xoperands[0], xoperands[1]))
	      output_asm_insn (\"sub %H0,%H0\", xoperands);
	    else
	      output_asm_insn (\"mov %1,%H0\", xoperands);
	  }
	else
	  output_asm_insn (\"mov %H1,%H0\", operands);
      }
    else if ((GET_CODE (operands[1]) == CONST_INT
	      || GET_CODE (operands[1]) == CONST_DOUBLE)
	     && val[0] == val[1])
      output_asm_insn (\"mov %L0,%H0\", operands);
    else
      output_asm_insn (\"mov %H1,%H0\", operands);
    return \"\";
  }
}

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

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

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

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

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

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

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

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=d,a,a,da,x,&!da") (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,da") (match_operand:SI 2 "nonmemory_operand" "J,J,L,dai,i,da")))] "" "@ inc %0 inc %0 inc4 %0 add %2,%0 add %2,%0 mov %2,%0;add %1,%0" [(set_attr "cc" "set_zn,none_0hit,none_0hit,set_zn,none_0hit,set_zn")])

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

(define_insn "subsi3" [(set (match_operand:SI 0 "register_operand" "=da") (minus:SI (match_operand:SI 1 "register_operand" "0") (match_operand:SI 2 "nonmemory_operand" "dai")))] "" "sub %2,%0" [(set_attr "cc" "set_zn")])

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

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

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

(define_insn "mulsi3" [(set (match_operand:SI 0 "register_operand" "=d") (mult:SI (match_operand:SI 1 "register_operand" "%0") (match_operand:SI 2 "register_operand" "d")))] "" "* { if (TARGET_MULT_BUG) return "nop;nop;mul %2,%0"; else return "mul %2,%0"; }" [(set_attr "cc" "set_zn")])

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

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

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

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

(define_insn "andsi3" [(set (match_operand:SI 0 "register_operand" "=d,d") (and:SI (match_operand:SI 1 "register_operand" "%0,0") (match_operand:SI 2 "nonmemory_operand" "N,di")))] "" "* { if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xff) return "extbu %0"; if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xffff) return "exthu %0"; if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x7fffffff) return "add %0,%0;lsr 1,%0"; if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x3fffffff) return "asl2 %0;lsr 2,%0"; if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x1fffffff) return "add %0,%0;asl2 %0;lsr 3,%0"; if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x0fffffff) return "asl2 %0,%0;asl2 %0;lsr 4,%0"; if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffffe) return "lsr 1,%0;add %0,%0"; if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffffc) return "lsr 2,%0;asl2 %0"; if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffff8) return "lsr 3,%0;add %0,%0;asl2 %0"; if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0xfffffff0) return "lsr 4,%0;asl2 %0;asl2 %0"; return "and %2,%0"; }" [(set_attr "cc" "none_0hit,set_znv")])

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

(define_insn "iorsi3" [(set (match_operand:SI 0 "register_operand" "=d") (ior:SI (match_operand:SI 1 "register_operand" "%0") (match_operand:SI 2 "nonmemory_operand" "di")))] "" "or %2,%0" [(set_attr "cc" "set_znv")])

;; ---------------------------------------------------------------------- ;; XOR INSTRUCTIONS ;; ----------------------------------------------------------------------

(define_insn "xorsi3" [(set (match_operand:SI 0 "register_operand" "=d") (xor:SI (match_operand:SI 1 "register_operand" "%0") (match_operand:SI 2 "nonmemory_operand" "di")))] "" "xor %2,%0" [(set_attr "cc" "set_znv")])

;; ---------------------------------------------------------------------- ;; NOT INSTRUCTIONS ;; ----------------------------------------------------------------------

(define_insn "one_cmplsi2" [(set (match_operand:SI 0 "register_operand" "=d") (not:SI (match_operand:SI 1 "register_operand" "0")))] "" "not %0" [(set_attr "cc" "set_znv")]) ;; ----------------------------------------------------------------- ;; BIT FIELDS ;; -----------------------------------------------------------------

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

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

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

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

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

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

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

(define_insn "" [(set (cc0) (zero_extract:SI (match_operand:QI 0 "general_operand" "R,d") (match_operand 1 "const_int_operand" "") (match_operand 2 "const_int_operand" "")))] "INTVAL (operands[1]) <= 8 && INTVAL (operands[2]) <= 7" "* { int len = INTVAL (operands[1]); int bit = INTVAL (operands[2]); int mask = 0; rtx xoperands[2];

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

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

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

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

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

;; Conditional jump instructions

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

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

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

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

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

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

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

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

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

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

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

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

;; Unconditional and other jump instructions.

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

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

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

;; Call subroutine with no return value.

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

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

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

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

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

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

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

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

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

(define_insn "zero_extendqisi2" [(set (match_operand:SI 0 "general_operand" "=d,d,d") (zero_extend:SI (match_operand:QI 1 "general_operand" "0,d,m")))] "" "@ extbu %0 mov %1,%0;extbu %0 movbu %1,%0" [(set_attr "cc" "none_0hit")])

(define_insn "zero_extendhisi2" [(set (match_operand:SI 0 "general_operand" "=d,d,d") (zero_extend:SI (match_operand:HI 1 "general_operand" "0,d,m")))] "" "@ exthu %0 mov %1,%0;exthu %0 movhu %1,%0" [(set_attr "cc" "none_0hit")])

;;- sign extension instructions

(define_insn "extendqisi2" [(set (match_operand:SI 0 "general_operand" "=d,d") (sign_extend:SI (match_operand:QI 1 "general_operand" "0,d")))] "" "@ extb %0 mov %1,%0;extb %0" [(set_attr "cc" "none_0hit")])

(define_insn "extendhisi2" [(set (match_operand:SI 0 "general_operand" "=d,d") (sign_extend:SI (match_operand:HI 1 "general_operand" "0,d")))] "" "@ exth %0 mov %1,%0;exth %0" [(set_attr "cc" "none_0hit")]) ;; ---------------------------------------------------------------------- ;; SHIFTS ;; ----------------------------------------------------------------------

(define_insn "ashlsi3" [(set (match_operand:SI 0 "register_operand" "=da,d,d,d,d") (ashift:SI (match_operand:SI 1 "register_operand" "0,0,0,0,0") (match_operand:QI 2 "nonmemory_operand" "J,K,M,L,di")))] "" "@ add %0,%0 asl2 %0 asl2 %0;add %0,%0 asl2 %0;asl2 %0 asl %S2,%0" [(set_attr "cc" "set_zn")])

(define_insn "lshrsi3" [(set (match_operand:SI 0 "register_operand" "=d") (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") (match_operand:QI 2 "nonmemory_operand" "di")))] "" "lsr %S2,%0" [(set_attr "cc" "set_zn")])

(define_insn "ashrsi3" [(set (match_operand:SI 0 "register_operand" "=d") (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") (match_operand:QI 2 "nonmemory_operand" "di")))] "" "asr %S2,%0" [(set_attr "cc" "set_zn")])

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

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

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

;; This insn restores the callee saved registers and does a return, it ;; can also deallocate stack space. (define_insn "return_internal_regs" [(const_int 0) (match_operand:SI 0 "const_int_operand" "i") (return)] "" "ret [d2,d3,a2,a3],%0" [(set_attr "cc" "clobber")])

(define_insn "store_movm" [(const_int 1)] "" "movm [d2,d3,a2,a3],(sp)" [(set_attr "cc" "clobber")])

(define_insn "return" [(return)] "can_use_return_insn ()" "* { rtx next = next_active_insn (insn);

if (next && GET_CODE (next) == JUMP_INSN && GET_CODE (PATTERN (next)) == RETURN) return ""; else return "rets"; }" [(set_attr "cc" "clobber")])

;; Try to combine consecutive updates of the stack pointer (or any ;; other register for that matter). (define_peephole [(set (match_operand:SI 0 "register_operand" "=dax") (plus:SI (match_dup 0) (match_operand 1 "const_int_operand" ""))) (set (match_dup 0) (plus:SI (match_dup 0) (match_operand 2 "const_int_operand" "")))] "" "* { operands[1] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[1])); return "add %1,%0"; }" [(set_attr "cc" "clobber")])

;; ;; We had patterns to check eq/ne, but the they don't work because ;; 0x80000000 + 0x80000000 = 0x0 with a carry out. ;; ;; The Z flag and C flag would be set, and we have no way to ;; check for the Z flag set and C flag clear. ;; ;; This will work on the mn10200 because we can check the ZX flag ;; if the comparison is in HImode. (define_peephole [(set (cc0) (match_operand:SI 0 "register_operand" "d")) (set (pc) (if_then_else (ge (cc0) (const_int 0)) (match_operand 1 "" "") (pc)))] "dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])" "add %0,%0;bcc %1" [(set_attr "cc" "clobber")])

(define_peephole [(set (cc0) (match_operand:SI 0 "register_operand" "d")) (set (pc) (if_then_else (lt (cc0) (const_int 0)) (match_operand 1 "" "") (pc)))] "dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])" "add %0,%0;bcs %1" [(set_attr "cc" "clobber")])

(define_peephole [(set (cc0) (match_operand:SI 0 "register_operand" "d")) (set (pc) (if_then_else (ge (cc0) (const_int 0)) (pc) (match_operand 1 "" "")))] "dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])" "add %0,%0;bcs %1" [(set_attr "cc" "clobber")])

(define_peephole [(set (cc0) (match_operand:SI 0 "register_operand" "d")) (set (pc) (if_then_else (lt (cc0) (const_int 0)) (pc) (match_operand 1 "" "")))] "dead_or_set_p (ins1, operands[0]) && REG_OK_FOR_INDEX_P (operands[0])" "add %0,%0;bcc %1" [(set_attr "cc" "clobber")])