;;- Machine description for the Motorola DSP56000/1 for GNU C compiler
;;   Copyright ( C ) 1988 Free Software Foundation, Inc.
;;

;; 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.

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

;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code
;;- updates for most instructions.

;;  %letter escapes for operand printing. (via PRINT_OPERAND).
;;  %d - print the accumulator name, disregard MEM_IN_STRUCT kludge.
;;  %e - print 1 after accumulator operand. No affect on non-accum reg.
;;  %f - print x: or y: before memory reference operand.
;;  %g - print alternate of x or y half-register.
;;  %h - print 0 after accumulator operand.
;;  %i - strip the 0/1 off an x or y half-register.
;;  %j - n register associated with r register.
;;  %k - print 2 after accumulator operand.
;;  %m - print the source reg name, without a trailing 0 or 1.
;;  %o - print the accumulator name with a trailing 10.

;;  %p - output this as a pointer size constant.
;;  %q - output this as an integer size constant.
;;  %r - output this as a long size constant.

;;
;;  ...........................................................................
;;
;;          MOVES, LOADS, STORES
;;
;;  ...........................................................................
;;

    
;; allow a PSImode value to be loaded into any register, but preferentially
;; load it into an A register. The A must come last - otherwise we risk 
;; messing up the code that does subunion stuff.

( define_expand "movpsi"
  [ ( set ( match_operand:PSI 0 "general_operand" "" )
	  ( match_operand:PSI 1 "general_operand" "" )) ]
  ""
  "
{
    if ( ! really_reg_p ( operands[0] ) && ! really_reg_p ( operands[1] ))
    {
	operands[1] = force_reg ( PSImode, operands[1] );
    }
}" )

( define_insn ""
  [ ( set
      ( match_operand:PSI 0 "general_operand" "=mr" )
      ( match_operand:PSI 1 "register_operand" "r" )) ]
  ""
  "*{ return move_pointer ( operands ); }" "CAN_ACCEPT_SUBREG_ACC" )

( define_insn ""
  [ ( set
      ( match_operand:PSI 0 "register_operand" "=r" )
      ( match_operand:PSI 1 "general_operand" "imr" )) ]
  ""
  "*{ return move_pointer ( operands ); }" "CAN_ACCEPT_SUBREG_ACC" )

( define_expand "movqi"
  [ ( set ( match_operand:QI 0 "general_operand" "" )
	  ( match_operand:QI 1 "general_operand" "" )) ]
  ""
  "
{
    if ( ! really_reg_p ( operands[0] ) && ! really_reg_p ( operands[1] ))
    {
	operands[1] = force_reg ( QImode, operands[1] );
    }
}" )

( define_insn ""
  [ ( set
      ( match_operand:QI 0 "general_operand" "=<>m,S,D" )
      ( match_operand:QI 1 "hard_register_operand" "r,r,r" )) ]
  ""
  "*{ return move_single_integer ( operands ); }" "CAN_ACCEPT_SUBREG_ACC" )

( define_insn ""
  [ ( set
      ( match_operand:QI 0 "general_operand" "=<>m,<>m,S,S,D,D" )
      ( match_operand:QI 1 "register_operand" "S,D,S,D,S,D" )) ]
  ""
  "*{ return move_single_integer ( operands ); }" "CAN_ACCEPT_SUBREG_ACC" )

( define_insn ""
  [ ( set
      ( match_operand:QI 0 "register_operand" "=S,D,S,D,S,D,S,D" )
      ( match_operand:QI 1 "general_operand" "i,i,<>m,<>m,S,S,D,D" )) ]
  ""
  "*{ return move_single_integer ( operands ); }" "CAN_ACCEPT_SUBREG_ACC" )

( define_expand "movsi"
  [ ( set ( match_operand:SI 0 "general_operand" "" )
	  ( match_operand:SI 1 "general_operand" "" )) ]
  ""
  "
{
    if ( ! really_reg_p ( operands[0] ) && ! really_reg_p ( operands[1] ))
    {
	operands[1] = force_reg ( SImode, operands[1] );
    }
}" )

( define_insn ""
  [ ( set
      ( match_operand:SI 0 "general_operand" "=<>m,S,D" )
      ( match_operand:SI 1 "hard_register_operand" "r,r,r" )) ]
  ""
  "*{ return move_single_integer ( operands ); }" "CAN_ACCEPT_SUBREG_ACC" )

( define_insn ""
  [ ( set
      ( match_operand:SI 0 "general_operand" "=<>m,<>m,S,S,D,D" )
      ( match_operand:SI 1 "register_operand" "S,D,S,D,S,D" )) ]
  ""
  "*{ return move_single_integer ( operands ); }" "CAN_ACCEPT_SUBREG_ACC" )

( define_insn ""
  [ ( set
      ( match_operand:SI 0 "register_operand" "=S,D,S,D,S,D,S,D" )
      ( match_operand:SI 1 "general_operand" "i,i,<>m,<>m,S,S,D,D" )) ]
  ""
  "*{ return move_single_integer ( operands ); }" "CAN_ACCEPT_SUBREG_ACC" )

( define_expand "movsz"
  [ ( set ( match_operand:SZ 0 "general_operand" "" )
	  ( match_operand:SZ 1 "general_operand" "" )) ]
  ""
  "
{
    if ( ! really_reg_p ( operands[0] ) && ! really_reg_p ( operands[1] ))
    {
	operands[1] = force_reg ( SZmode, operands[1] );
    }
}" )

( define_insn ""
  [ ( set
      ( match_operand:SZ 0 "general_operand" "=<>m,<>m,S,S,D,D" )
      ( match_operand:SZ 1 "register_operand" "S,D,S,D,S,D" )) ]
  ""
  "*{ return move_single_integer ( operands ); }" "CAN_ACCEPT_SUBREG_ACC" )

( define_insn ""
  [ ( set
      ( match_operand:SZ 0 "register_operand" "=S,D,S,D,S,D,S,D" )
      ( match_operand:SZ 1 "general_operand" "i,i,<>m,<>m,S,S,D,D" )) ]
  ""
  "*{ return move_single_integer ( operands ); }" "CAN_ACCEPT_SUBREG_ACC" )

( define_expand "movxsz"
  [ ( set ( match_operand:XSZ 0 "general_operand" "" )
	  ( match_operand:XSZ 1 "general_operand" "" )) ]
  ""
  "
{
    if ( ! really_reg_p ( operands[0] ) && ! really_reg_p ( operands[1] ))
    {
	operands[1] = force_reg ( XSZmode, operands[1] );
    }
}" )

( define_insn ""
  [ ( set
      ( match_operand:XSZ 0 "general_operand" "=<>m,D" )
      ( match_operand:XSZ 1 "register_operand" "D,D" )) ]
  ""
  "*{ return move_single_integer ( operands ); }" "CAN_ACCEPT_SUBREG_ACC" )

( define_insn ""
  [ ( set
      ( match_operand:XSZ 0 "register_operand" "=D,D,D" )
      ( match_operand:XSZ 1 "general_operand" "i,<>m,D" )) ]
  ""
  "*{ return move_single_integer ( operands ); }" "CAN_ACCEPT_SUBREG_ACC" )

( define_expand "movdi"
  [ ( set ( match_operand:DI 0 "general_operand" "" )
	  ( match_operand:DI 1 "general_operand" "" )) ]
  ""
  "
{
    if ( ! really_reg_p ( operands[0] ) && ! really_reg_p ( operands[1] ))
    {
	operands[1] = force_reg ( DImode, operands[1] );
    }
}" )

( define_insn ""
  [ ( set
      ( match_operand:DI 0 "general_operand" "=<>m,<>m,S,S,D,D" )
      ( match_operand:DI 1 "register_operand" "S,D,S,D,S,D" )) ]
  ""
  "*{ return move_double_integer ( 0, operands ); }" "CAN_ACCEPT_SUBREG_ACC" )

( define_insn ""
  [ ( set
      ( match_operand:DI 0 "register_operand" "=S,D,S,D,S,D,S,D" )
      ( match_operand:DI 1 "general_operand" "Gi,Gi,<>m,<>m,S,S,D,D" )) ]
  ""
  "*{ return move_double_integer ( 0, operands ); }" "CAN_ACCEPT_SUBREG_ACC" )

( define_expand "movdz"
  [ ( set ( match_operand:DZ 0 "general_operand" "" )
	  ( match_operand:DZ 1 "general_operand" "" )) ]
  ""
  "
{
    if ( ! really_reg_p ( operands[0] ) && ! really_reg_p ( operands[1] ))
    {
	operands[1] = force_reg ( DZmode, operands[1] );
    }
}" )

( define_insn ""
  [ ( set
      ( match_operand:DZ 0 "general_operand" "=<>m,<>m,S,S,D,D" )
      ( match_operand:DZ 1 "register_operand" "S,D,S,D,S,D" )) ]
  ""
  "*{ return move_double_integer ( 0, operands ); }" "CAN_ACCEPT_SUBREG_ACC" )

( define_insn ""
  [ ( set
      ( match_operand:DZ 0 "register_operand" "=S,D,S,D,S,D,S,D" )
      ( match_operand:DZ 1 "general_operand" "Gi,Gi,<>m,<>m,S,S,D,D" )) ]
  ""
  "*{ return move_double_integer ( 0, operands ); }" "CAN_ACCEPT_SUBREG_ACC" )

( define_expand "movxdz"
  [ ( set ( match_operand:XDZ 0 "general_operand" "" )
	  ( match_operand:XDZ 1 "general_operand" "" )) ]
  ""
  "
{
    if ( ! really_reg_p ( operands[0] ) && ! really_reg_p ( operands[1] ))
    {
	operands[1] = force_reg ( XDZmode, operands[1] );
    }
}" )

( define_insn ""
  [ ( set
      ( match_operand:XDZ 0 "general_operand" "=<>m,D" )
      ( match_operand:XDZ 1 "register_operand" "D,D" )) ]
  ""
  "*{ return move_double_integer ( 0, operands ); }" "CAN_ACCEPT_SUBREG_ACC" )

( define_insn ""
  [ ( set
      ( match_operand:XDZ 0 "register_operand" "=D,D,D" )
      ( match_operand:XDZ 1 "general_operand" "Gi,<>m,D" )) ]
  ""
  "*{ return move_double_integer ( 0, operands ); }" "CAN_ACCEPT_SUBREG_ACC" )

( define_expand "movsf"
  [ ( set ( match_operand:SF 0 "general_operand" "" )
	  ( match_operand:SF 1 "general_operand" "" )) ]
  ""
  "
{
    if ( ! really_reg_p ( operands[0] ) && ! really_reg_p ( operands[1] ))
    {
	operands[1] = force_reg ( SFmode, operands[1] );
    }
}" )

( define_insn ""
  [ ( set
      ( match_operand:SF 0 "general_operand" "=<>m,<>m,S,S,D,D" )
      ( match_operand:SF 1 "register_operand" "S,D,S,D,S,D" )) ]
  ""
  "*{ return move_double_integer ( 1, operands ); }" "CAN_ACCEPT_SUBREG_ACC" )

( define_insn ""
  [ ( set
      ( match_operand:SF 0 "register_operand" "=S,D,S,D,S,D,S,D" )
      ( match_operand:SF 1 "general_operand" "G,G,<>m,<>m,S,S,D,D" )) ]
  ""
  "*{ return move_double_integer ( 1, operands ); }" "CAN_ACCEPT_SUBREG_ACC" )

( define_expand "movdf"
  [ ( set ( match_operand:DF 0 "general_operand" "" )
	  ( match_operand:DF 1 "general_operand" "" )) ]
  ""
  "
{
    if ( ! really_reg_p ( operands[0] ) && ! really_reg_p ( operands[1] ))
    {
	operands[1] = force_reg ( DFmode, operands[1] );
    }
}" )
  
( define_insn ""
  [ ( set
      ( match_operand:DF 0 "general_operand" "=<>m,<>m,S,S,D,D" )
      ( match_operand:DF 1 "register_operand" "S,D,S,D,S,D" )) ]
  ""
  "*{ return move_double_integer ( 1, operands ); }" "CAN_ACCEPT_SUBREG_ACC" )

( define_insn ""
  [ ( set
      ( match_operand:DF 0 "register_operand" "=S,D,S,D,S,D,S,D" )
      ( match_operand:DF 1 "general_operand" "G,G,<>m,<>m,S,S,D,D" )) ]
  ""
  "*{ return move_double_integer ( 1, operands ); }" "CAN_ACCEPT_SUBREG_ACC" )

;;
;;  ...........................................................................
;;
;;          BLOCKMOVES
;;
;;  ...........................................................................
;;

( define_expand "movstrsi"
  [ ( parallel [ ( set ( match_operand:BLK 0 "memory_operand" "" )
		       ( match_operand:BLK 1 "memory_operand" "" ))
		 ( use ( match_operand:SI 2 "general_operand" "" ))
		 ( use ( match_operand:SI 3 "general_operand" "" )) ] ) ]
  ""
  "
{
    rtx op0_reg, op1_reg, cpy_reg;

    op0_reg = gen_reg_rtx ( PSImode );
    emit_move_insn ( op0_reg, force_reg ( PSImode, XEXP ( operands[0], 0 )));
    
    op1_reg = gen_reg_rtx ( PSImode );
    emit_move_insn ( op1_reg, force_reg ( PSImode, XEXP ( operands[1], 0 )));
    
    cpy_reg = gen_reg_rtx ( DImode );

    if ( CONST_DOUBLE == GET_CODE ( operands[2] ))
    {
	operands[2] = gen_rtx ( CONST_INT, VOIDmode, 
			       CONST_DOUBLE_LOW ( operands[2] ));
    }
    
    emit_insn (
	       gen_rtx ( PARALLEL, VOIDmode,
			gen_rtvec ( 7,
				   gen_rtx ( CLOBBER, VOIDmode, op0_reg ),
				   gen_rtx ( CLOBBER, VOIDmode, op1_reg ),
				   gen_rtx ( USE, VOIDmode, operands[2] ),
				   gen_rtx ( CLOBBER, VOIDmode, cpy_reg ),
				   gen_rtx ( SET, VOIDmode, operands[0],
					    operands[1] ),
				   gen_rtx ( USE, VOIDmode, op0_reg ),
				   gen_rtx ( USE, VOIDmode, op1_reg ))));
    DONE;
}" )

( define_insn ""
  [ ( parallel [ ( clobber ( match_operand:PSI 0 "register_operand" "=A,A" ))
		 ( clobber ( match_operand:PSI 1 "register_operand" "=A,A" ))
		 ( use ( match_operand:SI 2 "immediate_operand" "i,i" ))
		 ( clobber ( match_operand:DI 3 "register_operand" "=S,D" ))
		 ( set ( match_operand:BLK 4 "memory_operand" "" )
		       ( match_operand:BLK 5 "memory_operand" "" ))
		 ( use ( match_operand:PSI 6 "register_operand" "0,0" ))
		 ( use ( match_operand:PSI 7 "register_operand" "1,1" )) ] ) ]
""
"*
{
    operands[8] = gen_label_rtx ( );

    if ( TARGET_L_MEMORY )
    {
	if ( IS_SRC_OR_MPY_P ( REGNO ( operands[3] )))
	{
	    switch ( INTVAL ( operands[2] ))
	    {
	    case 1:
		return \"move	l:(%1),%m3\;\"
		       \"move	%m3,l:(%0)\";

	    case 2:
		return \"move	l:(%1)+,%m3\;\"
		       \"move	%m3,l:(%0)+\;\"
		       \"move	l:(%1),%m3\;\"
		       \"move	%m3,l:(%0)\";
	    case 3:
		if ( ! TARGET_CONSERVE_P_MEM )
		{
		    return \"move	l:(%1)+,%m3\;\"
		           \"move	%m3,l:(%0)+\;\"
		           \"move	l:(%1)+,%m3\;\"
		           \"move	%m3,l:(%0)+\;\"
		           \"move	l:(%1),%m3\;\"
		           \"move	%m3,l:(%0)\";
		}
		
	    default:
		return \"do	#%c2,%l8\;\"
		       \"move	l:(%1)+,%m3\;\"
		       \"move	%m3,l:(%0)+\\n%l8\";
	    }
	}
	else
	{
	    switch ( INTVAL ( operands[2] ))
	    {
	    case 1:
		return \"move	l:(%1),%o3\;\"
		       \"move	%o3,l:(%0)\";

	    case 2:
		return \"move	l:(%1)+,%o3\;\"
		       \"move	%o3,l:(%0)+\;\"
		       \"move	l:(%1),%o3\;\"
		       \"move	%o3,l:(%0)\";
	    case 3:
		if ( ! TARGET_CONSERVE_P_MEM )
		{
		    return \"move	l:(%1)+,%o3\;\"
		           \"move	%o3,l:(%0)+\;\"
		           \"move	l:(%1)+,%o3\;\"
		           \"move	%o3,l:(%0)+\;\"
		           \"move	l:(%1),%o3\;\"
		           \"move	%o3,l:(%0)\";
		}

	    default:
		return \"do	#%c2,%l8\;\"
		       \"move	l:(%1)+,%o3\;\"
		       \"move	%o3,l:(%0)+\\n%l8\";
	    }
	}
    }
    else /* single mem space. */
    {
	switch ( INTVAL ( operands[2] ))
	{
	case 1:
	    return fms ( \"move	@:(%1),%3\;\"
			 \"move	%3,@:(%0)\" );
	case 2:
	    return fms ( \"move	@:(%1)+,%3\;\"
			 \"move	%3,@:(%0)+\;\"
			 \"move	@:(%1),%3\;\"
			 \"move	%3,@:(%0)\" );
	case 3:
		if ( ! TARGET_CONSERVE_P_MEM )
		{
		    return fms ( \"move	@:(%1)+,%3\;\"
				 \"move	%3,@:(%0)+\;\"
				 \"move	@:(%1)+,%3\;\"
				 \"move	%3,@:(%0)+\;\"
				 \"move	@:(%1),%3\;\"
				 \"move	%3,@:(%0)\" );
		}

	default:
	    return fms ( \"do	#%c2,%l8\;\"
			 \"move	@:(%1)+,%3\;\"
			 \"move	%3,@:(%0)+\\n%l8\" );
	}
    }
}" )

;;
;;  ...........................................................................
;;
;;          ADDITIONS
;;
;;  ...........................................................................
;;

;; We provide quick software emulation via a subroutine that emulates
;; a floating point instruction.

( define_insn "adddf3"
  [ ( set ( match_operand:DF 0 "general_operand" "=D" )
          ( plus:DF ( match_operand:DF 1 "general_operand" "0" )
                    ( match_operand:DF 2 "general_operand" "D" ))) ]
  ""
  "jsr	fadd_%2%0" )

( define_insn "addsf3"
  [ ( set ( match_operand:SF 0 "general_operand" "=D" )
          ( plus:SF ( match_operand:SF 1 "general_operand" "0" )
                    ( match_operand:SF 2 "general_operand" "D" ))) ]
  ""
  "jsr	fadd_%2%0" )

;; Note that we MUST provide for inc/dec with a constant of one. The reload
;; pass may arbitrarily spill a regsiter post/pre inc/dec and will attempt to
;; perform the increment on the fly by itself. It does not consult the code
;; generator to see whether ( PSI <= PSI + CONST_INT ) is a valid insn.

( define_insn "addpsi3"
  [ ( set ( match_operand:PSI 0 "register_operand" "=A,D,D" )
	  ( plus:PSI ( match_operand:PSI 1 "register_operand" "0,0,0" )
		     ( match_operand:SI 2 "general_operand" "i,S,D" ))) ]
  ""
  "*
{
    if ( ! which_alternative )
    {
	switch ( INTVAL ( operands[2] ))
	{
	case 0:
	    return \"\";
	    
	case 1:
	    return \"move	(%0)+\";
	    
	case -1:
	    return \"move	(%0)-\";
	    
	default:
	    if ( load_n_reg_p ( operands[0], operands[2] ))
	    {
		return \"move	#%p2,%j0\;\"
		       \"move	(%0)+%j0\";
	    }
	    else
	    {
		return \"move	(%0)+%j0\";
	    }
	}
    }
    else
    {
	return \"add	%2,%0\";
    }
}" )

;; we need this extra shape because addition commutes. 

( define_insn ""
  [ ( set ( match_operand:PSI 0 "register_operand" "=A,D,D" )
	  ( plus:PSI ( match_operand:SI 1 "general_operand" "i,D,S" )
		     ( match_operand:PSI 2 "register_operand" "0,0,0" ))) ]
  ""
  "*
{
    if ( ! which_alternative )
    {
	switch ( INTVAL ( operands[2] ))
	{
	case 0:
	    return \"\";
	    
	case 1:
	    return \"move	(%0)+\";
	    
	case -1:
	    return \"move	(%0)-\";
	    
	default:
	    if ( load_n_reg_p ( operands[0], operands[2] ))
	    {
		return \"move	#%p1,%j0\;\"
		       \"move	(%0)+%j0\";
	    }
	    else
	    {
		return \"move	(%0)+%j0\";
	    }
	}
    }
    else
    {
	return \"add	%1,%0\";
    }
}" )

;; this insn is here because insn_extract does not detect commutable operands.

( define_insn ""
  [ ( set ( match_operand:PSI 0 "register_operand" "=D,D" )
	  ( plus:PSI ( match_operand:SI 1 "register_operand" "S,D" )
		     ( match_operand:PSI 2 "register_operand" "0,0" ))) ]
  ""
  "add	%1,%0" )

( define_insn "addsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "=D,D" )
          ( plus:SI ( match_operand:SI 1 "register_operand" "0,0" )
                    ( match_operand:SI 2 "register_operand" "S,D" ))) ]
  ""
  "*
{
    if ( REGNO ( operands[2] ) == REGNO ( operands[0] ))
    {
	return \"asl	%0\";
    }
    else
    {
	return \"add	%2,%0\";
    }
}" )

( define_insn "addsz3"
  [ ( set ( match_operand:SZ 0 "register_operand" "=D,D" )
          ( plus:SZ ( match_operand:SZ 1 "register_operand" "0,0" )
                    ( match_operand:SZ 2 "register_operand" "S,D" ))) ]
  ""
  "*
{
    if ( REGNO ( operands[2] ) == REGNO ( operands[0] ))
    {
	return \"asl	%0\";
    }
    else
    {
	return \"add	%2,%0\";
    }
}" )

( define_expand "adddi3"
  [ ( set
      ( match_operand:DI 0 "register_operand" "" )
      ( plus:DI ( match_operand:DI 1 "register_operand" "" )
		( match_operand:DI 2 "register_or_002_crement_operand" "" ))) ]
  ""
  "" )

( define_insn ""
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( match_operator:DI 1 "plus_or_minus_operator"
	      [ ( match_operand:DI 2 "register_operand" "0" )
	        ( match_operand:DI 3 "crement_operand" "F" ) ] )) ]
  "TARGET_56002"
  "*
{
    if ((( PLUS == GET_CODE ( operands[1] )) &&
	 ( 1 == CONST_DOUBLE_LOW ( operands[3] ))) ||
	(( MINUS == GET_CODE ( operands[1] )) &&
	 ( -1 == CONST_DOUBLE_LOW ( operands[3] ))))
    {
	return \"inc	%0\";
    }
    else
    {
	return \"dec	%0\";
    }
}" )

( define_insn ""
  [ ( set ( match_operand:DI 0 "register_operand" "=D,D" )
          ( plus:DI ( match_operand:DI 1 "register_operand" "0,0" )
                    ( match_operand:DI 2 "register_operand" "S,D" ))) ]
  ""
  "*
{
    if ( IS_SRC_OR_MPY_P ( REGNO ( operands[2] )))
    {
	return \"add     %i2,%0\";
    }
    else
    {
	if ( REGNO ( operands[2] ) == REGNO ( operands[0] ))
	{
	    return \"asl	%0\";
	}
	else
	{
	    return \"add	%2,%0\";
	}
    }
}" )

;;
;;  ...........................................................................
;;
;;          SUBTRACTIONS
;;
;;  ...........................................................................
;;

;; We provide quick software emulation via a subroutine that emulates
;; a floating point instruction.

( define_insn "subsf3"
  [ ( set ( match_operand:SF 0 "general_operand" "=D" )
          ( minus:SF ( match_operand:SF 1 "general_operand" "0" )
                     ( match_operand:SF 2 "general_operand" "D" ))) ]
  ""
  "*
{ return ( REGNO ( operands[0] ) == REGNO ( operands[2] )) ?
      \"clr	%0\" : \"jsr	fsub_%2%0\"; }" )

( define_insn "subdf3"
  [ ( set ( match_operand:DF 0 "general_operand" "=D" )
          ( minus:DF ( match_operand:DF 1 "general_operand" "0" )
                     ( match_operand:DF 2 "general_operand" "D" ))) ]
  ""
  "*
{ return ( REGNO ( operands[0] ) == REGNO ( operands[2] )) ?
      \"clr	%0\" : \"jsr	fsub_%2%0\"; }" )

;; There are really two ways that subtraction can be used with pointers:
;; 1) PSI <= PSI - SI, and 2) SI <= PSI - PSI. Because of the way that the
;; GNU CC is structured in optabs.c, subtraction type (1) must be labeled as
;; subpsi3. Version 1.7 of optabs.c has code that, when turned on, will allow
;; you use type (2) as subpsi3. Currently, the shape for type (2) should
;; never be used: c-typeck.c converts the operands of a (2) to SImode before
;; the subtraction. This has no effect on us currently, however, if we should
;; try to use the address alu for PSImode adds and subtracts, it will.

;; Addendum: the shape for (2) could actually be generated by the DSP loop
;; optimization code in computing the number of loop iterations.

;; Note that we MUST provide for inc/dec with a constant of one. The reload
;; pass may arbitrarily spill a regsiter post/pre inc/dec and will attempt to
;; perform the increment on the fly by itself. It does not consult the code
;; generator to see whether ( PSI <= PSI + CONST_INT ) is a valid insn.

( define_insn "subpsi3"
  [ ( set ( match_operand:PSI 0 "register_operand" "=A,D,D" )
	  ( minus:PSI ( match_operand:PSI 1 "register_operand" "0,0,0" )
		      ( match_operand:SI 2 "general_operand" "i,S,D" ))) ]
  ""
  "*
{
    if ( ! which_alternative )
    {
	switch ( INTVAL ( operands[2] ))
	{
	case 0:
	    return \"\";
	    
	case 1:
	    return \"move	(%0)-\";
	    
	case -1:
	    return \"move	(%0)+\";
	    
	default:
	    if ( load_n_reg_p ( operands[0], operands[2] ))
	    {
		return \"move	#%p2,%j0\;\"
		       \"move	(%0)-%j0\";
	    }
	    else
	    {
		return \"move	(%0)-%j0\";
	    }
	}
    }
    else
    {
	return \"sub	%2,%0\";
    }
}" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D,D" )
	  ( minus:PSI ( match_operand:PSI 1 "register_operand" "0,0" )
		      ( match_operand:PSI 2 "register_operand" "S,D" ))) ]
  ""
  "sub	%2,%0" )

( define_insn "subsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "=D,D" )
	  ( minus:SI ( match_operand:SI 1 "register_operand" "0,0" )
		     ( match_operand:SI 2 "register_operand" "D,S" ))) ]
  ""
  "*
{
    if ( REGNO ( operands[2] ) == REGNO ( operands[0] ))
    {
	return \"clr	%0\";
    }
    else
    {
	return \"sub	%2,%0\";
    }
}" )

( define_expand "subdi3"
  [ ( set ( match_operand:DI 0 "register_operand" "" )
	  ( minus:DI 
	    ( match_operand:DI 1 "register_operand" "" )
	    ( match_operand:DI 2 "register_or_002_crement_operand" "" ))) ]
  ""
  "" )

( define_insn ""
  [ ( set ( match_operand:DI 0 "register_operand" "=D,D" )
	  ( minus:DI ( match_operand:DI 1 "register_operand" "0,0" )
		     ( match_operand:DI 2 "register_operand" "S,D" ))) ]
  ""
  "*
{
    if ( IS_SRC_OR_MPY_P ( REGNO ( operands[2] )))
    {
	return \"sub     %i2,%0\";
    }
    else
    {
	if ( REGNO ( operands[2] ) == REGNO ( operands[0] ))
	{
	    return \"clr	%0\";
	}
	else
	{
	    return \"sub	%2,%0\";
	}
    }
}" )


( define_insn "subsz3"
  [ ( set ( match_operand:SZ 0 "register_operand" "=D,D" )
	  ( minus:SZ ( match_operand:SZ 1 "register_operand" "0,0" )
		     ( match_operand:SZ 2 "register_operand" "D,S" ))) ]
  "TARGET_C_FOR_DSP"
  "*
{
    if ( REGNO ( operands[2] ) == REGNO ( operands[0] ))
    {
	return \"clr	%0\";
    }
    else
    {
	return \"sub	%2,%0\";
    }
}" )

;;
;;  ...........................................................................
;;
;;          MULTIPLICATIONS AND DIVISIONS
;;
;;  ...........................................................................
;;

;; We provide quick software emulation via a subroutine that emulates
;; a floating point instruction.

( define_insn "muldf3"
  [ ( set ( match_operand:DF 0 "general_operand" "=D" )
          ( mult:DF ( match_operand:DF 1 "general_operand" "0" )
                    ( match_operand:DF 2 "general_operand" "D" ))) ]
  ""
  "jsr	fmpy_%2%0" )

( define_insn "mulsf3"
  [ ( set ( match_operand:SF 0 "general_operand" "=D" )
          ( mult:SF ( match_operand:SF 1 "general_operand" "0" )
                    ( match_operand:SF 2 "general_operand" "D" ))) ]
  ""
  "jsr	fmpy_%2%0" )

;; We have two shapes for mac+ and two shapes for mac-, because the mult may
;; turn up as either operand of the plus/minus.

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( plus:SI ( match_operand:SI 1 "register_operand" "0" )
		    ( mult:SI ( match_operand:SI 2 "register_operand" "%S" )
			      ( match_operand:SI 3 "register_operand" "R" ))))]
  ""
  "*
{
    if ( MEM_IN_STRUCT_P ( insn ))
    {
	if ( RTX_UNCHANGING_P ( insn ))
	{
	    return \"mac	+%2,%3,%0\";
	}
	return \"mac	+%2,%3,%0\;\"
	       \"asr	%0\;\"
	       \"move	%h0,%0\";
    }
    else if ( RTX_UNCHANGING_P ( insn ))
    {
	return \"move	%0,%h0\;\"
	       \"asl	%0\;\"
	       \"mac	+%2,%3,%0\";
    }
    return \"move	%0,%h0\;\"
           \"asl	%0\;\"
	   \"mac	+%2,%3,%0\;\"
	   \"asr	%0\;\"
	   \"move	%h0,%0\";
}" "INPUT_NORM_OPTIONAL | OUTPUT_NORM_OPTIONAL" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( plus:SI ( mult:SI ( match_operand:SI 1 "register_operand" "%S" )
			      ( match_operand:SI 2 "register_operand" "R" ))
		    ( match_operand:SI 3 "register_operand" "0" ))) ]
  ""
  "*
{
    if ( MEM_IN_STRUCT_P ( insn ))
    {
	if ( RTX_UNCHANGING_P ( insn ))
	{
	    return \"mac	+%1,%2,%0\";
	}
	return \"mac	+%1,%2,%0\;\"
	       \"asr	%0\;\"
	       \"move	%h0,%0\";
    }
    else if ( RTX_UNCHANGING_P ( insn ))
    {
	return \"move	%0,%h0\;\"
	       \"asl	%0\;\"
	       \"mac	+%1,%2,%0\";
    }
    return \"move	%0,%h0\;\"
           \"asl	%0\;\"
	   \"mac	+%1,%2,%0\;\"
	   \"asr	%0\;\"
	   \"move	%h0,%0\";
}" "INPUT_NORM_OPTIONAL | OUTPUT_NORM_OPTIONAL" )


( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( minus:SI ( match_operand:SI 1 "register_operand" "0" )
		     ( mult:SI ( match_operand:SI 2 "register_operand" "%S" )
			       ( match_operand:SI 3 "register_operand" "R" ))))
  ]
  ""
  "*
{
    if ( MEM_IN_STRUCT_P ( insn ))
    {
	if ( RTX_UNCHANGING_P ( insn ))
	{
	    return \"mac	-%2,%3,%0\";
	}
	return \"mac	-%2,%3,%0\;\"
	       \"asr	%0\;\"
	       \"move	%h0,%0\";
    }
    else if ( RTX_UNCHANGING_P ( insn ))
    {
	return \"move	%0,%h0\;\"
	       \"asl	%0\;\"
	       \"mac	-%2,%3,%0\";
    }
    return \"move	%0,%h0\;\"
           \"asl	%0\;\"
	   \"mac	-%2,%3,%0\;\"
	   \"asr	%0\;\"
	   \"move	%h0,%0\";
}" "INPUT_NORM_OPTIONAL | OUTPUT_NORM_OPTIONAL" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( plus:SI ( match_operand:SI 1 "register_operand" "0" )
		    ( mult:SI ( match_operand:SI 2 "register_operand" "%S" )
			      ( match_operand:SI 3 "pow_two_operand" "i" )))) ]
  "TARGET_56002"
  "*
{
    operands[4] = gen_rtx
	( CONST_INT, VOIDmode, floor_log2 ( INTVAL ( operands[3] )));
    
    if ( MEM_IN_STRUCT_P ( insn ))
    {
	if ( RTX_UNCHANGING_P ( insn ))
	{
	    return \"mac	+%2,#(23-%c4),%0\";
	}
	return \"mac	+%2,#(23-%c4),%0\;\"
	       \"asr	%0\;\"
	       \"move	%h0,%0\";
    }
    else if ( RTX_UNCHANGING_P ( insn ))
    {
	return \"move	%0,%h0\;\"
	       \"asl	%0\;\"
	       \"mac	+%2,#(23-%c4),%0\";
    }
    return \"move	%0,%h0\;\"
           \"asl	%0\;\"
	   \"mac	+%2,#(23-%c4),%0\;\"
	   \"asr	%0\;\"
	   \"move	%h0,%0\";
}" "INPUT_NORM_OPTIONAL | OUTPUT_NORM_OPTIONAL" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( plus:SI ( mult:SI ( match_operand:SI 1 "register_operand" "%S" )
			      ( match_operand:SI 2 "pow_two_operand" "i" ))
		    ( match_operand:SI 3 "register_operand" "0" ))) ]
  "TARGET_56002"
  "*
{
    operands[4] = gen_rtx
	( CONST_INT, VOIDmode, floor_log2 ( INTVAL ( operands[2] )));
    
    if ( MEM_IN_STRUCT_P ( insn ))
    {
	if ( RTX_UNCHANGING_P ( insn ))
	{
	    return \"mac	+%1,#(23-%c4),%0\";
	}
	return \"mac	+%1,#(23-%c4),%0\;\"
	       \"asr	%0\;\"
	       \"move	%h0,%0\";
    }
    else if ( RTX_UNCHANGING_P ( insn ))
    {
	return \"move	%0,%h0\;\"
	       \"asl	%0\;\"
	       \"mac	+%1,#(23-%c4),%0\";
    }
    return \"move	%0,%h0\;\"
           \"asl	%0\;\"
	   \"mac	+%1,#(23-%c4),%0\;\"
	   \"asr	%0\;\"
	   \"move	%h0,%0\";
}" "INPUT_NORM_OPTIONAL | OUTPUT_NORM_OPTIONAL" )


( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( minus:SI ( match_operand:SI 1 "register_operand" "0" )
		     ( mult:SI ( match_operand:SI 2 "register_operand" "%S" )
			       ( match_operand:SI 3 "pow_two_operand" "i" ))))]
  "TARGET_56002"
  "*
{
    operands[4] = gen_rtx
	( CONST_INT, VOIDmode, floor_log2 ( INTVAL ( operands[3] )));
    
    if ( MEM_IN_STRUCT_P ( insn ))
    {
	if ( RTX_UNCHANGING_P ( insn ))
	{
	    return \"mac	-%2,#(23-%c4),%0\";
	}
	return \"mac	-%2,#(23-%c4),%0\;\"
	       \"asr	%0\;\"
	       \"move	%h0,%0\";
    }
    else if ( RTX_UNCHANGING_P ( insn ))
    {
	return \"move	%0,%h0\;\"
	       \"asl	%0\;\"
	       \"mac	-%2,#(23-%c4),%0\";
    }
    return \"move	%0,%h0\;\"
           \"asl	%0\;\"
	   \"mac	-%2,#(23-%c4),%0\;\"
	   \"asr	%0\;\"
	   \"move	%h0,%0\";
}" "INPUT_NORM_OPTIONAL | OUTPUT_NORM_OPTIONAL" )

;; we have a quick (breaks calling convention rules) subr. act as an inst.

( define_insn "muldi3"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
          ( mult:DI ( match_operand:DI 1 "register_operand" "0" )
                    ( match_operand:DI 2 "register_operand" "D" ))) ]
  ""
  "jsr	lmpy_%2%0" )

;; normal, boring mults follow.

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( mult:SI ( match_operand:SI 1 "register_operand" "%S" )
		    ( match_operand:SI 2 "pow_two_operand" "i" ))) ]
  "TARGET_56002"
  "*
{
    operands[3] = gen_rtx 
	( CONST_INT, VOIDmode, floor_log2 ( INTVAL ( operands[2] )));
    
    if ( RTX_UNCHANGING_P ( insn ))
    {
	return \"mpy	%1,#(23-%c3),%0\";
    }
    return \"mpy	%1,#(24-%c3),%0\;\"
           \"move	%h0,%0\";
}" "OUTPUT_NORM_OPTIONAL" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( mult:SI ( match_operand:SI 1 "register_operand" "%S" )
		    ( match_operand:SI 2 "register_operand" "R" ))) ]
  ""
  "*
{
    if ( RTX_UNCHANGING_P ( insn ))
    {
	return \"mpy	%2,%1,%0\";
    }
    return \"mpy	%2,%1,%0\;\"
           \"asr	%0\;\"
	   \"move	%h0,%0\";
}" "OUTPUT_NORM_OPTIONAL" )

( define_expand "mulsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "" )
	  ( mult:SI ( match_operand:SI 1 "register_or_002_pow_two_operand" "" )
		    ( match_operand:SI 2 "register_operand" "" ))) ]
  ""
  "" )

( define_insn "umulsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( umult:SI ( match_operand:SI 1 "register_operand" "%S" )
		     ( match_operand:SI 2 "register_operand" "R" ))) ]
  ""
  "mpy	%2,%1,%0;asr	%0;move	%h0,%0" )

( define_insn "mulsz3"
  [ ( set ( match_operand:SZ 0 "register_operand" "=D" )
	  ( mult:SZ ( match_operand:SZ 1 "register_operand" "%S" )
		    ( match_operand:SZ 2 "register_operand" "R" ))) ]
  ""
  "mpyr	%2,%1,%0" )

( define_insn "muldz3"
  [ ( set ( match_operand:DZ 0 "register_operand" "=D" )
          ( mult:DZ ( match_operand:DZ 1 "register_operand" "%S" )
                    ( match_operand:DZ 2 "register_operand" "R" ))) ]
  "TARGET_C_FOR_DSP"
  "mpy  %2,%1,%0" "CCS_SET_CORRECTLY" )


;; We have two shapes for mac+ and two shapes for mac-, because the mult may
;; turn up as either operand of the plus/minus.

( define_insn ""
  [ ( set ( match_operand:SZ 0 "register_operand" "=D" )
	  ( plus:SZ ( match_operand:SZ 1 "register_operand" "0" )
		    ( mult:SZ ( match_operand:SZ 2 "register_operand" "%S" )
			      ( match_operand:SZ 3 "register_operand" "R" ))))]
  ""
  "macr	+%2,%3,%0" )

( define_insn ""
  [ ( set ( match_operand:SZ 0 "register_operand" "=D" )
	  ( plus:SZ ( mult:SZ ( match_operand:SZ 1 "register_operand" "%S" )
			      ( match_operand:SZ 2 "register_operand" "R" ))
		    ( match_operand:SZ 3 "register_operand" "0" ))) ]
  ""
  "macr	+%1,%2,%0" )

( define_insn ""
  [ ( set ( match_operand:SZ 0 "register_operand" "=D" )
	  ( minus:SZ ( match_operand:SZ 1 "register_operand" "0" )
		     ( mult:SZ ( match_operand:SZ 2 "register_operand" "%S" )
			       ( match_operand:SZ 3 "register_operand" "R" ))))
  ]
  ""
  "macr	-%2,%3,%0" )

( define_insn ""
  [ ( set ( match_operand:SZ 0 "register_operand" "=D" )
	  ( plus:SZ ( match_operand:SZ 1 "register_operand" "0" )
		    ( mult:SZ ( match_operand:SZ 2 "register_operand" "%S" )
			      ( match_operand:SZ 3 "pow_two_operand" "i" )))) ]
  "TARGET_56002"
  "*
{
    operands[4] = gen_rtx
	( CONST_INT, VOIDmode, floor_log2 ( INTVAL ( operands[3] )));
    
    if ( MEM_IN_STRUCT_P ( insn ))
    {
	if ( RTX_UNCHANGING_P ( insn ))
	{
	    return \"mac	+%2,#(23-%c4),%0\";
	}
	return \"mac	+%2,#(23-%c4),%0\;\"
	       \"asr	%0\;\"
	       \"move	%h0,%0\";
    }
    else if ( RTX_UNCHANGING_P ( insn ))
    {
	return \"move	%0,%h0\;\"
	       \"asl	%0\;\"
	       \"mac	+%2,#(23-%c4),%0\";
    }
    return \"move	%0,%h0\;\"
           \"asl	%0\;\"
	   \"mac	+%2,#(23-%c4),%0\;\"
	   \"asr	%0\;\"
	   \"move	%h0,%0\";
}" "INPUT_NORM_OPTIONAL | OUTPUT_NORM_OPTIONAL" )

( define_insn ""
  [ ( set ( match_operand:SZ 0 "register_operand" "=D" )
	  ( plus:SZ ( mult:SZ ( match_operand:SZ 1 "register_operand" "%S" )
			      ( match_operand:SZ 2 "pow_two_operand" "i" ))
		    ( match_operand:SZ 3 "register_operand" "0" ))) ]
  "TARGET_56002"
  "*
{
    operands[4] = gen_rtx
	( CONST_INT, VOIDmode, floor_log2 ( INTVAL ( operands[2] )));
    
    if ( MEM_IN_STRUCT_P ( insn ))
    {
	if ( RTX_UNCHANGING_P ( insn ))
	{
	    return \"mac	+%1,#(23-%c4),%0\";
	}
	return \"mac	+%1,#(23-%c4),%0\;\"
	       \"asr	%0\;\"
	       \"move	%h0,%0\";
    }
    else if ( RTX_UNCHANGING_P ( insn ))
    {
	return \"move	%0,%h0\;\"
	       \"asl	%0\;\"
	       \"mac	+%1,#(23-%c4),%0\";
    }
    return \"move	%0,%h0\;\"
           \"asl	%0\;\"
	   \"mac	+%1,#(23-%c4),%0\;\"
	   \"asr	%0\;\"
	   \"move	%h0,%0\";
}" "INPUT_NORM_OPTIONAL | OUTPUT_NORM_OPTIONAL" )


( define_insn ""
  [ ( set ( match_operand:SZ 0 "register_operand" "=D" )
	  ( minus:SZ ( match_operand:SZ 1 "register_operand" "0" )
		     ( mult:SZ ( match_operand:SZ 2 "register_operand" "%S" )
			       ( match_operand:SZ 3 "pow_two_operand" "i" ))))]
  "TARGET_56002"
  "*
{
    operands[4] = gen_rtx
	( CONST_INT, VOIDmode, floor_log2 ( INTVAL ( operands[3] )));
    
    if ( MEM_IN_STRUCT_P ( insn ))
    {
	if ( RTX_UNCHANGING_P ( insn ))
	{
	    return \"mac	-%2,#(23-%c4),%0\";
	}
	return \"mac	-%2,#(23-%c4),%0\;\"
	       \"asr	%0\;\"
	       \"move	%h0,%0\";
    }
    else if ( RTX_UNCHANGING_P ( insn ))
    {
	return \"move	%0,%h0\;\"
	       \"asl	%0\;\"
	       \"mac	-%2,#(23-%c4),%0\";
    }
    return \"move	%0,%h0\;\"
           \"asl	%0\;\"
	   \"mac	-%2,#(23-%c4),%0\;\"
	   \"asr	%0\;\"
	   \"move	%h0,%0\";
}" "INPUT_NORM_OPTIONAL | OUTPUT_NORM_OPTIONAL" )

( define_insn ""
  [ ( set ( match_operand:SZ 0 "register_operand" "=D" )
	  ( mult:SZ ( match_operand:SZ 1 "register_operand" "%S" )
		    ( match_operand:SZ 2 "pow_two_operand" "i" ))) ]
  "TARGET_56002"
  "*
{
    operands[3] = gen_rtx 
	( CONST_INT, VOIDmode, floor_log2 ( INTVAL ( operands[2] )));
    
    if ( RTX_UNCHANGING_P ( insn ))
    {
	return \"mpy	%1,#(23-%c3),%0\";
    }
    return \"mpy	%1,#(24-%c3),%0\;\"
           \"move	%h0,%0\";
}" "OUTPUT_NORM_OPTIONAL" )

;; We provide quick software emulation via a subroutine that emulates
;; a floating point instruction.

( define_insn "divdi3"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
          ( div:DI ( match_operand:DI 1 "register_operand" "0" )
                   ( match_operand:DI 2 "register_operand" "D" ))) ]
  ""
  "*
{ return ( REGNO ( operands[0] ) == REGNO ( operands[2] )) ?
      \"clr	%0\;move	#>1,%0\" :
      \"jsr	ldiv_%2%0\"; }" )

( define_insn "moddi3"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
          ( mod:DI ( match_operand:DI 1 "register_operand" "0" )
                   ( match_operand:DI 2 "register_operand" "D" ))) ]
  ""
  "*
{ return ( REGNO ( operands[0] ) == REGNO ( operands[2] )) ?
      \"clr	%0\" :
      \"jsr	lmod_%2%0\"; }" )

( define_insn "divsf3"
  [ ( set ( match_operand:SF 0 "general_operand" "=D" )
          ( div:SF ( match_operand:SF 1 "general_operand" "0" )
                   ( match_operand:SF 2 "general_operand" "D" ))) ]
  ""
  "*
{ return ( REGNO ( operands[0] ) == REGNO ( operands[2] )) ?
      \"move	#>4194304,%0\;move	#>8192,%h0\" :
	  \"jsr	fdiv_%2%0\"; }" )

( define_insn "divdf3"
  [ ( set ( match_operand:DF 0 "general_operand" "=D" )
          ( div:DF ( match_operand:DF 1 "general_operand" "0" )
                   ( match_operand:DF 2 "general_operand" "D" ))) ]
  ""
  "*
{ return ( REGNO ( operands[0] ) == REGNO ( operands[2] )) ?
      \"move	#>4194304,%0\;move	#>8192,%h0\" :
	  \"jsr	fdiv_%2%0\"; }" )

( define_insn "udivsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( udiv:SI ( match_operand:SI 1 "register_operand" "0" )
		    ( match_operand:SI 2 "register_operand" "D" ))) ]
  ""
  "*
{ return ( REGNO ( operands[0] ) == REGNO ( operands[2] )) ?
      \"clr	%0\;move	#>1,%0\" :
      \"jsr	udiv_%2%0\"; }" )

( define_insn "umodsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( umod:SI ( match_operand:SI 1 "register_operand" "0" )
		    ( match_operand:SI 2 "register_operand" "D" ))) ]
  ""
  "*
{ return ( REGNO ( operands[0] ) == REGNO ( operands[2] )) ?
      \"clr	%0\" :
      \"jsr	umod_%2%0\"; }" )

( define_expand "divsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "" )
	  ( div:SI ( match_operand:SI 1 "register_operand" "" )
		   ( match_operand:SI 2 "register_operand" "" ))) ]
  ""
  "
{
    emit_insn (
	       gen_rtx ( PARALLEL, VOIDmode,
			gen_rtvec ( 3,
				   gen_rtx ( SET, VOIDmode, operands[0],
					    gen_rtx ( DIV, SImode, 
						     operands[1],
						     operands[2] )),
				   gen_rtx ( CLOBBER, VOIDmode, 
					    gen_reg_rtx ( SImode )),
				   gen_rtx ( CLOBBER, VOIDmode, 
					    gen_reg_rtx ( SImode )))));
    DONE;
}" )

( define_insn ""
  [ ( parallel [ ( set ( match_operand:SI 0 "register_operand" "=D" )
		       ( div:SI ( match_operand:SI 1 "register_operand" "0" )
				( match_operand:SI 2 "register_operand" "S" )))
		 ( clobber ( match_operand:SI 3 "register_operand" "=D" ))
		 ( clobber ( match_operand:SI 4 "register_operand" "=S" )) ] )]
  "TARGET_CONSERVE_P_MEM"
  "jsr	idiv_%2%0" )

( define_insn ""
  [ ( parallel [ ( set ( match_operand:SI 0 "register_operand" "=D" )
		       ( div:SI ( match_operand:SI 1 "register_operand" "0" )
				( match_operand:SI 2 "register_operand" "S" )))
		 ( clobber ( match_operand:SI 3 "register_operand" "=&D" ))
		 ( clobber ( match_operand:SI 4 "register_operand" "=&S" )) ] )
  ]
  ""
  "*
{
    operands[5] = gen_label_rtx ( );
    
    if ( TARGET_REP ) 
    {
	return  \"tfr	%0,%3\;\"
		\"abs	%0\;\"
		\"clr	%0	%e0,%4\;\"
		\"move	%4,%h0\;\"
		\"asl	%0\;\"
		\"rep	#$18\;\"
		\"div	%2,%0\;\"
		\"eor	%2,%3\;\"
		\"jpl	%l5\;\"
		\"neg	%0\"
	  \"\\n%l5\;\"
	        \"move	%h0,%0\";
    }
    else
    {
	operands[6] = gen_label_rtx ( );

	return  \"tfr	%0,%3\;\"
	        \"abs	%0\;\"
		\"clr	%0	%e0,%4\;\"
		\"move	%4,%h0\;\"
		\"asl	%0\;\"
		\"do	#$18,%l6\;\"
		\"div	%2,%0\"
	  \"\\n%l6\;\"
	        \"eor	%2,%3\;\"
		\"jpl	%l5\;\"
		\"neg	%0\"
	  \"\\n%l5\;\"
	        \"move	%h0,%0\";
    }
}" )

( define_expand "modsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "" )
	  ( mod:SI ( match_operand:SI 1 "register_operand" "" )
		   ( match_operand:SI 2 "register_operand" "" ))) ]
  ""
  "
{
    emit_insn (
	       gen_rtx ( PARALLEL, VOIDmode,
			gen_rtvec ( 3,
				   gen_rtx ( SET, VOIDmode, operands[0],
					    gen_rtx ( MOD, SImode, 
						     operands[1],
						     operands[2] )),
				   gen_rtx ( CLOBBER, VOIDmode, 
					    gen_reg_rtx ( SImode )),
				   gen_rtx ( CLOBBER, VOIDmode, 
					    gen_reg_rtx ( SImode )))));
    DONE;
}" )

( define_insn ""
  [ ( parallel [ ( set ( match_operand:SI 0 "register_operand" "=D" )
		       ( mod:SI ( match_operand:SI 1 "register_operand" "0" )
				( match_operand:SI 2 "register_operand" "S" )))
		 ( clobber ( match_operand:SI 3 "register_operand" "=D" ))
		 ( clobber ( match_operand:SI 4 "register_operand" "=S" )) ] )]
  "TARGET_CONSERVE_P_MEM"
  "jsr	imod_%2%0" )

( define_insn ""
  [ ( parallel [ ( set ( match_operand:SI 0 "register_operand" "=D" )
		       ( mod:SI ( match_operand:SI 1 "register_operand" "0" )
				( match_operand:SI 2 "register_operand" "S" )))
		 ( clobber ( match_operand:SI 3 "register_operand" "=&D" ))
		 ( clobber ( match_operand:SI 4 "register_operand" "=&S" )) ] )
  ]
  ""
  "*
{
    operands[5] = gen_label_rtx ( );
    
    if ( TARGET_REP ) 
    {
     return  \"tfr	%0,%3\;\"
	     \"abs	%0\;\"
	     \"clr	%0	%e0,%4\;\"
	     \"move	%4,%h0\;\"
	     \"asl	%0\;\"
	     \"rep	#$18\;\"
	     \"div	%2,%0\;\"
	     \"move	%e0,%4\;\"
	     \"move	%2,%0\;\"
	     \"abs	%0\;\"
	     \"add	%4,%0\;\"
	     \"asr	%0\;\"
	     \"tst	%3\;\"
	     \"jge	%l5\;\"
	     \"neg	%0\"
	\"\\n%l5\";
    }
    else
    {
	operands[6] = gen_label_rtx ( );

	return  \"tfr	%0,%3\;\"
	        \"abs	%0\;\"
		\"clr	%0	%e0,%4\;\"
		\"move	%4,%h0\;\"
		\"asl	%0\;\"
		\"do	#$18,%l6\;\"
		\"div	%2,%0\"
	\"\\n%l6\;\"
	        \"move	%e0,%4\;\"
		\"move	%2,%0\;\"
		\"abs	%0\;\"
		\"add	%4,%0\;\"
		\"asr	%0\;\"
		\"tst	%3\;\"
		\"jge	%l5\;\"
		\"neg	%0\"
	\"\\n%l5\";
    }
}" )

;;
;;  ...........................................................................
;;
;;          NEGATIONS
;;
;;  ...........................................................................
;;

;; We provide quick software emulation via a subroutine that emulates
;; a floating point instruction.

( define_insn "negdf2"
  [ ( set ( match_operand:DF 0 "general_operand" "=D" )
          ( neg:DF ( match_operand:DF 1 "general_operand" "0" ))) ]
  ""
  "jsr	fneg_%0" )

( define_insn "negsf2"
  [ ( set ( match_operand:SF 0 "general_operand" "=D" )
          ( neg:SF ( match_operand:SF 1 "general_operand" "0" ))) ]
  ""
  "jsr	fneg_%0" )

( define_insn "negsi2"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( neg:SI ( match_operand:SI 1 "register_operand" "0" ))) ]
  ""
  "neg	%0" )

( define_insn "negdi2"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( neg:DI ( match_operand:DI 1 "register_operand" "0" ))) ]
  ""
  "neg	%0" )

( define_insn "negsz2"
  [ ( set ( match_operand:SZ 0 "register_operand" "=D" )
          ( neg:SZ ( match_operand:SZ 1 "register_operand" "0" ))) ]
  "TARGET_C_FOR_DSP"
  "neg  %0  ; from negsz2" "IFCCABLE_OP_CODE | CCS_SET_CORRECTLY" )
 
( define_insn "negdz2"
  [ ( set ( match_operand:DZ 0 "register_operand" "=D" )
          ( neg:DZ ( match_operand:DZ 1 "register_operand" "0" ))) ]
  "TARGET_C_FOR_DSP"
  "neg  %0  ; from negdz2" "IFCCABLE_OP_CODE | CCS_SET_CORRECTLY" )

;;
;;  ...........................................................................
;;
;;          ABSOLUTE VALUES
;;
;;  ...........................................................................
;;

( define_insn "abssi2"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( abs:SI ( match_operand:SI 1 "register_operand" "0" ))) ]
  ""
  "abs	%0" )

( define_insn "absdi2"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( abs:DI ( match_operand:DI 1 "register_operand" "0" ))) ]
  ""
  "abs	%0" )

;;
;;  ...........................................................................
;;
;;          LOGICAL AND
;;
;;  ...........................................................................
;;

( define_insn "andsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( and:SI ( match_operand:SI 1 "register_operand" "0" )
		   ( match_operand:SI 2 "register_operand" "S" ))) ]
  ""
  "and	%2,%0\;move	%e0,%0" )

( define_insn ""
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( and:DI ( match_operand:DI 1 "register_operand" "0" )
		   ( match_operand:DI 2 "register_operand" "S" ))) ]
  "TARGET_CONSERVE_P_MEM"
  "jsr	land_%m2%0" )

( define_insn "anddi3"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( and:DI ( match_operand:DI 1 "register_operand" "0" )
		   ( match_operand:DI 2 "register_operand" "S" ))) ]
  ""
  "*return fms ( \"and	%g2,%0	%h0,@:(r6)\;\"
  		 \"move	%e0,%h0\;\"
		 \"move	@:(r6),%e0\;\"
		 \"and	%2,%0\;\"
		 \"move	%e0,@:(r6)\;\"
		 \"move	%h0,%0\;\"
		 \"move	@:(r6),%h0\" );" )

;;
;;  ...........................................................................
;;
;;          LOGICAL INCLUSIVE OR
;;
;;  ...........................................................................
;;

( define_insn "iorsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( ior:SI ( match_operand:SI 1 "register_operand" "0" )
		   ( match_operand:SI 2 "register_operand" "S" ))) ]
  ""
  "or	%2,%0\;move	%e0,%0" )

( define_insn ""
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( ior:DI ( match_operand:DI 1 "register_operand" "0" )
		   ( match_operand:DI 2 "register_operand" "S" ))) ]
  "TARGET_CONSERVE_P_MEM"
  "jsr	lior_%m2%0" )

( define_insn "iordi3"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( ior:DI ( match_operand:DI 1 "register_operand" "0" )
		   ( match_operand:DI 2 "register_operand" "S" ))) ]
  ""
  "*return fms ( \"or	%g2,%0	%h0,@:(r6)\;\"
		 \"move	%e0,%h0\;\"
		 \"move	@:(r6),%e0\;\"
		 \"or	%2,%0\;\"
		 \"move	%e0,@:(r6)\;\"
		 \"move	%h0,%0\;\"
		 \"move	@:(r6),%h0\" );" )
;;
;;  ...........................................................................
;;
;;          LOGICAL EXCLUSIVE OR
;;
;;  ...........................................................................
;;

( define_insn "xorsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( xor:SI ( match_operand:SI 1 "register_operand" "0" )
		   ( match_operand:SI 2 "register_operand" "S" ))) ]
  ""
  "eor	%2,%0\;move	%e0,%0" )

( define_insn ""
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( xor:DI ( match_operand:DI 1 "register_operand" "0" )
		   ( match_operand:DI 2 "register_operand" "S" ))) ]
  "TARGET_CONSERVE_P_MEM"
  "jsr	lxor_%m2%0" )

( define_insn "xordi3"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( xor:DI ( match_operand:DI 1 "register_operand" "0" )
		   ( match_operand:DI 2 "register_operand" "S" ))) ]
  ""
  "*return fms ( \"eor	%g2,%0	%h0,@:(r6)\;\"
		 \"move	%e0,%h0\;\"
		 \"move	@:(r6),%e0\;\"
		 \"eor	%2,%0\;\"
		 \"move	%e0,@:(r6)\;\"
		 \"move	%h0,%0\;\"
		 \"move	@:(r6),%h0\" );" )
;;
;;  ...........................................................................
;;
;;          ONE'S COMPLEMENT
;;
;;  ...........................................................................
;;

( define_insn "one_cmplsi2"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( not:SI ( match_operand:SI 1 "register_operand" "0" ))) ]
  ""
  "not	%0\;move	%e0,%0" )

( define_insn ""
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( not:DI ( match_operand:DI 1 "register_operand" "0" ))) ]
  "TARGET_CONSERVE_P_MEM"
  "jsr	lnot_%0" )

( define_insn "one_cmpldi2"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( not:DI ( match_operand:DI 1 "register_operand" "0" ))) ]
  ""
  "*return fms ( \"not	%0	%h0,@:(r6)\;\"
		 \"move	%e0,%h0\;\"
		 \"move	@:(r6),%e0\;\"
		 \"not	%0\;\"
		 \"move	%e0,@:(r6)\;\"
		 \"move	%h0,%0\;\"
		 \"move	@:(r6),%h0\" );" )

;;
;;  ...........................................................................
;;
;;          ARITHMETIC SHIFTS
;;
;;  ...........................................................................
;;

;; note that we preceed each shift insn by an unnamed insn. the unnamed insn
;; is used to catch shifts with constant shift counts before said constants
;; are promoted to registers. 

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( ashift:SI ( match_operand:SI 1 "register_operand" "S" )
		      ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  "TARGET_56002 &&
 ( 2 < INTVAL ( operands[2] ) && 24 > INTVAL ( operands[2] ))"
  "mpy	%1,#(24-%c2),%0\;move	%h0,%0" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( ashift:SI ( match_operand:SI 1 "register_operand" "0" )
		      ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  ""
  "*
{
    if ( 1 == INTVAL ( operands[2] ))
    {
	return \"asl	%0\;\"
	       \"move	%e0,%0\";
    }
    else if ( 2 == INTVAL ( operands[2] ))
    {
	return \"asl	%0\;\"
	       \"asl	%0\;\"
	       \"move	%e0,%0\";
    }
    else
    {
	operands[3] = copy_rtx ( operands[2] );
	INTVAL ( operands[3] ) &= 0xfff;
	    
	if ( TARGET_REP )
	{
	    return \"rep	#%c3\;\"
		   \"asl	%0\;\"
		   \"move	%e0,%0\";
	}
	else
	{
	    operands[4] = gen_label_rtx ( );
	    
	    return \"do	#%c3,%l4\;\"
	           \"asl	%0\"
	      \"\\n%l4\;\"
	           \"move	%e0,%0\";
	}
    }
}" )

( define_insn "ashlsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( ashift:SI ( match_operand:SI 1 "register_operand" "0" )
		      ( match_operand:SI 2 "general_operand" "D" ))) ]
  ""
  "*
{
    operands[3] = gen_label_rtx ( );
    
    if ( TARGET_REP )
    {
	return \"tst	%2\;\"
	       \"jeq	%l3\;\"
	       \"rep	%2\;\"
	       \"asl	%0\;\"
	       \"move	%e0,%0\"
          \"\\n%l3\";
    }
    else
    {
	operands[4] = gen_label_rtx ( );
	
	return \"tst	%2\;\"
	       \"jeq	%l3\;\"
	       \"do	%2,%l4\;\"
	       \"asl	%0\"
	  \"\\n%l4\;\"
	       \"move	%e0,%0\"
	  \"\\n%l3\";
    }
}")

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( ashiftrt:SI ( match_operand:SI 1 "register_operand" "S" )
			( match_operand:SI 2 "immediate_operand" "i" ))) ]
  "TARGET_56002 &&
 ( 2 < INTVAL ( operands[2] ) && 24 > INTVAL ( operands[2] ))"
  "mpy	%1,#%c2,%0\;move	%e0,%0" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( ashiftrt:SI ( match_operand:SI 1 "register_operand" "0" )
			( match_operand:SI 2 "immediate_operand" "i" ))) ]
  ""
  "*
{
    if ( 1 == INTVAL ( operands[2] ))
    {
	return \"move	%e0,%0\;\"
	       \"asr	%0\;\"
	       \"move	%e0,%0\";
    }
    else if ( 2 == INTVAL ( operands[2] ))
    {
	return \"move	%e0,%0\;\"
	       \"asr	%0\;\"
	       \"asr	%0\;\"
	       \"move	%e0,%0\";
    }
    else
    {
	operands[3] = copy_rtx ( operands[2] );
	INTVAL ( operands[3] ) &= 0xfff;
	
	if ( TARGET_REP )
	{
	    return \"move	%e0,%0\;\"
		   \"rep	#%c3\;\"
		   \"asr	%0\;\"
		   \"move	%e0,%0\";
	}
	else
	{
	    operands[4] = gen_label_rtx ( );
	    
	    return \"move	%e0,%0\;\"
	           \"do	#%c3,%l4\;\"
		   \"asr	%0\"
	      \"\\n%l4\;\"
	           \"move	%e0,%0\";
	}
    }
}" )

( define_insn "ashrsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
     ( ashiftrt:SI ( match_operand:SI 1 "register_operand" "0" )
                   ( match_operand:SI 2 "general_operand" "D" ))) ]
  ""
  "*
{
    operands[3] = gen_label_rtx ( );
    
    if ( TARGET_REP )
    {
	return \"tst	%2\;\"
	       \"jeq	%l3\;\"
	       \"move	%e0,%0\;\"
	       \"rep	%2\;\"
	       \"asr	%0\;\"
	       \"move	%e0,%0\"
	  \"\\n%l3\";
    }
    else
    {
	operands[4] = gen_label_rtx ( );
	
	return \"tst	%2\;\"
	       \"jeq	%l3\;\"
	       \"move	%e0,%0\;\"
	       \"do	%2,%l4\;\"
	       \"asr	%0\"
	  \"\\n%l4\;\"
	       \"move	%e0,%0\"
	  \"\\n%l3\";
    }
}")

( define_insn ""
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
     ( ashift:DI ( match_operand:DI 1 "register_operand" "0" )
                 ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  ""
  "*
{
    switch ( INTVAL ( operands[2] ))
    {
    case 1:
	return \"asl	%0\";

    case 2:
	return \"asl	%0\;\"
	       \"asl	%0\";

    case 3:
	return \"asl	%0\;\"
	       \"asl	%0\;\"
	       \"asl	%0\";

    case 24:
	return \"move	%h0,%0\";

    default:
	operands[3] = copy_rtx ( operands[2] );
	INTVAL ( operands[3] ) &= 0xfff;
	
	if ( TARGET_REP )
	{
	    return \"rep	#%c3\;\"
		   \"asl	%0\";
	}
	else
	{
	    operands[4] = gen_label_rtx ( );
	    
	    return \"do	#%c3,%l4\;\"
	           \"asl	%0\"
	      \"\\n%l4\";
	}
    }	
}" )

( define_insn "ashldi3"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
     ( ashift:DI ( match_operand:DI 1 "register_operand" "0" )
                 ( match_operand:SI 2 "general_operand" "D" ))) ]
  ""
  "*
{
    operands[3] = gen_label_rtx ( );
    
    if ( TARGET_REP )
    {
	return \"tst	%d2\;\"
	       \"jeq	%l3\;\"
	       \"rep	%2\;\"
	       \"asl	%0\"
	  \"\\n%l3\";
    }
    else
    {
	return \"tst	%d2\;\"
	       \"jeq	%l3\;\"
	       \"do	%2,%l3\;\"
	       \"asl	%0\"
	  \"\\n%l3\";
    }
}")

( define_insn ""
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
     ( ashiftrt:DI ( match_operand:DI 1 "register_operand" "0" )
                   ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  ""
  "*
{
    if ( 1 == INTVAL ( operands[2] ))
    {
	return fms ( \"move	%h0,@:(r6)\;\"
	             \"move	%e0,%0\;\"
	             \"move	@:(r6),%h0\;\"
	             \"asr	%0\" );
    }
    else if ( 2 == INTVAL ( operands[2] ))
    {
	return fms ( \"move	%h0,@:(r6)\;\"
	             \"move	%e0,%0\;\"
	             \"move	@:(r6),%h0\;\"
	             \"asr	%0\;\"
	             \"asr	%0\" );
    }
    else
    {
	operands[3] = copy_rtx ( operands[2] );
	INTVAL ( operands[3] ) &= 0xfff;
	
	if ( TARGET_REP )
	{
	    return fms ( \"move	%h0,@:(r6)\;\"
		         \"move	%e0,%0\;\"
		         \"move	@:(r6),%h0\;\"
		         \"rep	#%c3\;\"
		         \"asr	%0\" );
	}
	else
	{
	    operands[4] = gen_label_rtx ( );
	    
	    return fms ( \"move	%h0,@:(r6)\;\"
	                 \"move	%e0,%0\;\"
		         \"move	@:(r6),%h0\;\"
		         \"do	#%c3,%l4\;\"
		         \"asr	%0\"
	           \"\\n%l4\" );
	}
    }
}" )

( define_insn "ashrdi3"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
     ( ashiftrt:DI ( match_operand:DI 1 "register_operand" "0" )
                   ( match_operand:SI 2 "general_operand" "D" ))) ]
  ""
  "*
{
    operands[3] = gen_label_rtx ( );

    if ( TARGET_REP )
    {
        return fms ( \"move	%h0,@:(r6)\;\"
	             \"move	%e0,%0\;\"
	             \"move	@:(r6),%h0\;\"
	             \"tst	%d2\;\"
	             \"jeq	%l3\;\"
	             \"rep	%2\;\"
	             \"asr	%0\"
	         \"\\n%l3\" );
    }
    else
    {
	return fms ( \"move	%h0,@:(r6)\;\"
	             \"move	%e0,%0\;\"
	             \"move	@:(r6),%h0\;\"
	             \"tst	%d2\;\"
	             \"jeq	%l3\;\"
	             \"do	%2,%l3\;\"
	             \"asr	%0\"
	         \"\\n%l3\" );
    }
}")

;;
;;  ...........................................................................
;;
;;          LOGICAL SHIFTS
;;
;;  ...........................................................................
;;

;; note that we preceed each shift insn by an unnamed insn. the unnamed insn
;; is used to catch shifts with constant shift counts before said constants
;; are promoted to registers. 

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
     ( lshift:SI ( match_operand:SI 1 "register_operand" "0" )
                 ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  ""
  "*
{
    if ( 1 == INTVAL ( operands[2] ))
    {
	return \"lsl	%0\";
    }
    else if ( 2 == INTVAL ( operands[2] ))
    {
	return \"lsl	%0\;\"
	       \"lsl	%0\";
    }
    else
    {
	operands[3] = copy_rtx ( operands[2] );
	INTVAL ( operands[3] ) &= 0xfff;
	
	if ( TARGET_REP )
	{
	    return \"rep	#%c3\;\"
		   \"lsl	%0\";
	}
	else
	{
	    operands[4] = gen_label_rtx ( );
	    
	    return \"do	#%c3,%l4\;\"
	           \"lsl	%0\"
	      \"\\n%l4\";
	}
    }
}" )

( define_insn "lshlsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
     ( lshift:SI ( match_operand:SI 1 "register_operand" "0" )
                 ( match_operand:SI 2 "general_operand" "D" ))) ]
  ""
  "*
{
    operands[3] = gen_label_rtx ( );
    
    if ( TARGET_REP )
    {
	return \"tst	%2\;\"
	       \"jeq	%l3\;\"
	       \"rep	%2\;\"
	       \"lsl	%0\"
	  \"\\n%l3\";
    }
    else
    {
	return \"tst	%2\;\"
	       \"jeq	%l3\;\"
	       \"do	%2,%l3\;\"
	       \"lsl	%0\"
	  \"\\n%l3\";
    }
}")

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
     ( lshiftrt:SI ( match_operand:SI 1 "register_operand" "0" )
                   ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  ""
  "*
{
    if ( 1 == INTVAL ( operands[2] ))
    {
	return \"lsr	%0\;\"
               \"move	%e0,%0\";
    }
    else if ( 2 == INTVAL ( operands[2] ))
    {
	return \"lsr	%0\;\"
               \"lsr	%0\;\"
               \"move	%e0,%0\";
    }
    else
    {
	operands[3] = copy_rtx ( operands[2] );
	INTVAL ( operands[3] ) &= 0xfff;
	
	if ( TARGET_REP )
	{
	    return \"rep	#%c3\;\"
		   \"lsr	%0\;\"
                   \"move	%e0,%0\";
	}
	else
	{
	    operands[4] = gen_label_rtx ( );
	    
	    return \"do	#%c3,%l4\;\"
	           \"lsr	%0\"
	           \"\\n%l4\;\"
                   \"move	%e0,%0\";
	}
    }
}" )

( define_insn "lshrsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
     ( lshiftrt:SI ( match_operand:SI 1 "register_operand" "0" )
                   ( match_operand:SI 2 "general_operand" "D" ))) ]
  ""
  "*
{
    operands[3] = gen_label_rtx ( );
    
    if ( TARGET_REP )
    {
	return \"tst	%2\;\"
	       \"jeq	%l3\;\"
	       \"rep	%2\;\"
	       \"lsr	%0\"
	  \"\\n%l3\";
    }
    else
    {
	return \"tst	%2\;\"
	       \"jeq	%l3\;\"
	       \"do	%2,%l3\;\"
	       \"lsr	%0\"
	  \"\\n%l3\";
    }
}")

( define_insn ""
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
     ( lshift:DI ( match_operand:DI 1 "register_operand" "0" )
                 ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  ""
  "*
{
    if ( 1 == INTVAL ( operands[2] ))
    {
	return \"asl	%0\";
    }
    else if ( 2 == INTVAL ( operands[2] ))
    {
	return \"asl	%0\;\"
	       \"asl	%0\";
    }
    else
    {
	operands[3] = copy_rtx ( operands[2] );
	INTVAL ( operands[3] ) &= 0xfff;
	
	if ( TARGET_REP )
	{
	    return \"rep	#%c3\;\"
		   \"asl	%0\";
	}
	else
	{	
	    operands[4] = gen_label_rtx ( );
	    
	    return \"do	#%c3,%l4\;\"
	           \"asl	%0\"
	      \"\\n%l4\";
	}
    }
}" )

( define_insn "lshldi3"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
     ( lshift:DI ( match_operand:DI 1 "register_operand" "0" )
                 ( match_operand:SI 2 "general_operand" "D" ))) ]
  ""
  "*
{
    operands[3] = gen_label_rtx ( );

    if ( TARGET_REP )
    {
	return \"tst	%d2\;\"
	       \"jeq	%l3\;\"
	       \"rep	%2\;\"
	       \"asl	%0\"
	  \"\\n%l3\";
    }
    else
    {
	return \"tst	%d2\;\"
	       \"jeq	%l3\;\"
	       \"do	%2,%l3\;\"
	       \"asl	%0\"
	  \"\\n%l3\";
    }
}")

( define_insn ""
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
     ( lshiftrt:DI ( match_operand:DI 1 "register_operand" "0" )
                   ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  ""
  "*
{
    if ( 1 == INTVAL ( operands[2] ))
    {
	return \"move	#0,%k0\;\"
	       \"asr	%0\";
    }
    else if ( 2 == INTVAL ( operands[2] ))
    {
	return \"move	#0,%k0\;\"
	       \"asr	%0\;\"
	       \"asr	%0\";
    }
    else
    {
	operands[3] = copy_rtx ( operands[2] );
	INTVAL ( operands[3] ) &= 0xfff;
	
	if ( TARGET_REP )
	{
	    return \"move	#0,%k0\;\"
		   \"rep	#%c3\;\"
		   \"asr	%0\";
	}
	else
	{
	    operands[4] = gen_label_rtx ( );
	    
	    return \"move	#0,%k0\;\"
	           \"do	#%c3,%l4\;\"
		   \"asr	%0\"
	      \"\\n%l4\";
	}
    }
}" )

( define_insn "lshrdi3"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
     ( lshiftrt:DI ( match_operand:DI 1 "register_operand" "0" )
                   ( match_operand:SI 2 "general_operand" "D" ))) ]
  ""
  "*
{
    operands[3] = gen_label_rtx ( );
    
    if ( TARGET_REP )
    {
	return \"tst	%d2\;\"
	       \"jeq	%l3\;\"
	       \"move	#0,%k0\;\"
	       \"rep	%2\;\"
	       \"asr	%0\"
	  \"\\n%l3\";
    }
    else
    {
	return \"tst	%d2\;\"
	       \"jeq	%l3\;\"
	       \"move	#0,%k0\;\"
	       \"do	%2,%l3\;\"
	       \"asr	%0\"
	  \"\\n%l3\";
    }
}")

;;
;;  ...........................................................................
;;
;;          ROTATIONS
;;
;;  ...........................................................................
;;

;; note that we preceed each shift insn by an unnamed insn. the unnamed insn
;; is used to catch shifts with constant shift counts before said constants
;; are promoted to registers. 

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
     ( rotate:SI ( match_operand:SI 1 "register_operand" "0" )
                 ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  ""
  "*
{
    if ( 1 == INTVAL ( operands[2] ))
    {
	return \"rol	%0\";
    }
    else if ( 2 == INTVAL ( operands[2] ))
    {
	return \"rol	%0\;\"
	       \"rol	%0\";
    }
    else
    {
	operands[3] = copy_rtx ( operands[2] );
	INTVAL ( operands[3] ) &= 0xfff;
	
	if ( TARGET_REP )
	{
	    return \"rep	#%c3\;\"
		   \"rol	%0\";
	}
	else
	{
	    operands[4] = gen_label_rtx ( );
	    
	    return \"do	#%c3,%l4\;\"
	           \"rol	%0\"
	      \"\\n%l4\";
	}
    }
}" )

( define_insn "rotlsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
     ( rotate:SI ( match_operand:SI 1 "register_operand" "0" )
                 ( match_operand:SI 2 "general_operand" "D" ))) ]
  ""
  "*
{
    operands[3] = gen_label_rtx ( );
    
    if ( TARGET_REP )
    {
	return \"tst	%2\;\"
	       \"jeq	%l3\;\"
	       \"rep	%2\;\"
	       \"rol	%0\"
	  \"\\n%l3\";
    }
    else
    {
	return \"tst	%2\;\"
	       \"jeq	%l3\;\"
	       \"do	%2,%l3\;\"
	       \"rol	%0\"
	  \"\\n%l3\";
    }
}")

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
     ( rotatert:SI ( match_operand:SI 1 "register_operand" "0" )
                   ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  ""
  "*
{
    if ( 1 == INTVAL ( operands[2] ))
    {
	return \"ror	%0\";
    }
    else if ( 2 == INTVAL ( operands[2] ))
    {
	return \"ror	%0\;\"
	       \"ror	%0\";
    }
    else
    {
	operands[3] = copy_rtx ( operands[2] );
	INTVAL ( operands[3] ) &= 0xfff;
	
	if ( TARGET_REP )
	{
	    return \"rep	#%c3\;\"
		   \"ror	%0\";
	}
	else
	{
	    operands[4] = gen_label_rtx ( );
	    
	    return \"do	#%c3,%l4\;\"
	           \"ror	%0\"
	      \"\\n%l4\";
	}
    }
}" )

( define_insn "rotrsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
     ( rotatert:SI ( match_operand:SI 1 "register_operand" "0" )
                   ( match_operand:SI 2 "general_operand" "D" ))) ]
  ""
  "*
{
    operands[3] = gen_label_rtx ( );
    
    if ( TARGET_REP )
    {
	return \"tst	%2\;\"
	       \"jeq	%l3\;\"
	       \"rep	%2\;\"
	       \"ror	%0\"
	  \"\\n%l3\";
    }
    else
    {
	return \"tst	%2\;\"
	       \"jeq	%l3\;\"
	       \"do	%2,%l3\;\"
	       \"ror	%0\"
	  \"\\n%l3\";
    }
}")

;;
;;  ...........................................................................
;;
;;          COMPARISONS
;;
;;  ...........................................................................
;;

;; We provide quick software emulation via a subroutine that emulates
;; a floating point instruction.

( define_insn "cmpdf"
  [ ( set ( cc0 )
          ( compare ( match_operand:DF 0 "register_operand" "D" )
                    ( match_operand:DF 1 "register_operand" "D" ))) ]
  ""
  "*
{
    int op0_is_a = ( DSP_A_REGNUM == REGNO ( operands[0] ));
    int op1_is_a = ( DSP_A_REGNUM == REGNO ( operands[1] ));
    
    if ( op0_is_a )
    {
	if ( op1_is_a )
	{
	    return \"andi	#$00,ccr\;\"
		   \"ori	#$14,ccr\";
	}
	else
	{
	    return \"jsr	fcmp_ba\";
	}
    }
    else
    {
	if ( op1_is_a )
	{
	    return \"jsr	fcmp_ab\";
	}
	else
	{
	    return \"andi	#$00,ccr\;\"
		   \"ori	#$14,ccr\";
	}
    }
}" )	

( define_insn "cmpsf"
  [ ( set ( cc0 )
          ( compare ( match_operand:SF 0 "register_operand" "D" )
                    ( match_operand:SF 1 "register_operand" "D" ))) ]
  ""
  "*
{
    int op0_is_a = ( DSP_A_REGNUM == REGNO ( operands[0] ));
    int op1_is_a = ( DSP_A_REGNUM == REGNO ( operands[1] ));
    
    if ( op0_is_a )
    {
	if ( op1_is_a )
	{
	    return \"andi	#$00,ccr\;\"
		   \"ori	#$14,ccr\";
	}
	else
	{
	    return \"jsr	fcmp_ba\";
	}
    }
    else
    {
	if ( op1_is_a )
	{
	    return \"jsr	fcmp_ab\";
	}
	else
	{
	    return \"andi	#$00,ccr\;\"
		   \"ori	#$14,ccr\";
	}
    }
}" )	

( define_expand "cmppsi"
  [ ( set ( cc0 )
	  ( compare ( match_operand:PSI 0 "register_operand" "" )
		    ( match_operand:PSI 1 "register_operand" "" ))) ]
  ""
  "
{
    emit_insn 
	( gen_rtx 
	 ( PARALLEL, VOIDmode, gen_rtvec
	  ( 3, 
	   gen_rtx ( SET, VOIDmode, cc0_rtx, 
		    gen_rtx ( COMPARE, PSImode, operands[0], operands[1] )),
	   gen_rtx ( CLOBBER, VOIDmode, gen_reg_rtx ( PSImode )),
	   gen_rtx ( CLOBBER, VOIDmode, gen_reg_rtx ( PSImode )))));
    DONE;
}" )

( define_insn ""
  [ ( parallel
      [ ( set ( cc0 )
	      ( compare ( match_operand:PSI 0 "register_operand" "A,A" )
			( match_operand:PSI 1 "register_operand" "A,A" )))
	( clobber ( match_operand:PSI 2 "register_operand" "=D,D" ))
	( clobber ( match_operand:PSI 3 "register_operand" "=S,D" )) ] )]
  ""
  "*
{
    extern rtx next_cc_relevancy ( );
    rtx relevant_insn, relevant_body;
    
    /* sometimes this compiler manages attempt ( compare ( reg x ) ( reg x )).
       the condition codes implied by this are obvious. we peek down the insn
       chain and discover the next_cc0_relevancy ( ). if we discover
       that the ccs are being set gratuitiously, we ignore this compare, 
       otherwise we change the cc0 consumer to be a constant load in the case
       of an Scond or a hard branch or nop in the case of a Bcond. */

    if ( REGNO ( operands[0] ) == REGNO ( operands[1] ))
    {
	relevant_insn = next_cc_relevancy ( insn );
	relevant_body = PATTERN ( relevant_insn );
	
	if ( JUMP_INSN == GET_CODE ( relevant_insn ))
	{
	    if (( IF_THEN_ELSE == GET_CODE ( relevant_body =
					    XEXP ( relevant_body, 1 ))) &&
		( CONST_INT != 
		 GET_CODE ( XEXP ( relevant_body, 0 ))))
	    {
		if (( GEU == GET_CODE ( XEXP ( relevant_body, 0 ))) ||
		    ( GE == GET_CODE ( XEXP ( relevant_body, 0 ))) ||
		    ( LEU == GET_CODE ( XEXP ( relevant_body, 0 ))) ||
		    ( LE == GET_CODE ( XEXP ( relevant_body, 0 ))) ||
		    ( EQU == GET_CODE ( XEXP ( relevant_body, 0 ))) ||
		    ( EQ == GET_CODE ( XEXP ( relevant_body, 0 ))))
		{
		    /* change ineq into const1_rtx because x == x always. */

		    if ( pc_rtx == XEXP ( XEXP ( PATTERN ( relevant_insn ),
						1 ), 1 ))
		    {
			PUT_CODE ( relevant_insn, NOTE );
			INSN_DELETED_P ( relevant_insn ) = 1;
		    }
		    else
		    {
			INSN_CODE ( relevant_insn ) = -1;

			XEXP ( PATTERN ( relevant_insn ), 1 ) =
			    XEXP ( XEXP ( PATTERN ( relevant_insn ), 1 ), 1 );
		    }
		}
		else
		{
		    /* otherwise change ineq into const0_rtx. */
		    
		    if ( pc_rtx == XEXP ( XEXP ( PATTERN ( relevant_insn ),
						1 ), 1 ))
		    {
			INSN_CODE ( relevant_insn ) = -1;

			XEXP ( PATTERN ( relevant_insn ), 1 ) =
			    XEXP ( XEXP ( PATTERN ( relevant_insn ), 1 ), 2 );
		    }
		    else
		    {
			PUT_CODE ( relevant_insn, NOTE );
			INSN_DELETED_P ( relevant_insn ) = 1;
		    }
		}
	    }
	}
	else if (( INSN == GET_CODE ( relevant_insn )) &&
		 ( PARALLEL == GET_CODE ( relevant_body )) &&
		 ( SET == GET_CODE ( relevant_body = 
				    XVECEXP ( relevant_body, 0, 0 ))) &&
		 ( 0 == strcmp ( \"ee\",
				GET_RTX_FORMAT ( GET_CODE ( XEXP ( relevant_body, 1 ))))) &&
		 ( cc0_rtx == XEXP ( XEXP ( relevant_body, 1 ), 0 )))
	{
	    if (( GEU == GET_CODE ( XEXP ( relevant_body, 1 ))) ||
		( GE == GET_CODE ( XEXP ( relevant_body, 1 ))) ||
		( LEU == GET_CODE ( XEXP ( relevant_body, 1 ))) ||
		( LE == GET_CODE ( XEXP ( relevant_body, 1 ))) ||
		( EQU == GET_CODE ( XEXP ( relevant_body, 1 ))) ||
		( EQ == GET_CODE ( XEXP ( relevant_body, 1 ))))
	    {
		/* change ineq into const1_rtx because x == x always. */

		XEXP ( relevant_body, 1 ) = const1_rtx;
	    }
	    else 
	    {
		/* otherwise change ineq into const0_rtx. */

		XEXP ( relevant_body, 1 ) = const0_rtx;
	    }
	    INSN_CODE ( relevant_insn ) = -1;
	}
	return \"\";
    }
    cc_status.mdep = CC_UNKNOWN;
    return \"move	%0,%2\;\"
           \"move	%1,%3\;\"
	   \"cmp	%3,%2\";
}" )

( define_insn ""
  [ ( set ( cc0 )
          ( compare ( match_operand:SI 0 "register_operand" "D" )
                    ( match_operand:SI 1 "register_operand" "D" ))) ]
  "UNSIGNED_COMPARE_P ( insn )"
  "*return output_compare ( insn, operands );" )

( define_insn "cmpsi"
  [ ( set ( cc0 )
          ( compare ( match_operand:SI 0 "register_operand" "D,D" )
                    ( match_operand:SI 1 "register_operand" "S,D" ))) ]
  ""
  "*return output_compare ( insn, operands );" )

( define_insn ""
  [ ( set ( cc0 )
          ( compare ( match_operand:DI 0 "register_operand" "D" )
                    ( match_operand:DI 1 "register_operand" "D" ))) ]
  "UNSIGNED_COMPARE_P( insn )"
  "*return output_compare ( insn, operands );" )

( define_insn "cmpdi"
  [ ( set ( cc0 )
          ( compare ( match_operand:DI 0 "register_operand" "D" )
                    ( match_operand:DI 1 "register_operand" "D" ))) ]
  ""
  "*return output_compare ( insn, operands );" )

( define_expand "cmpsz"
  [ ( set ( cc0 )
          ( compare ( match_operand:SZ 0 "register_operand" "" )
                    ( match_operand:SZ 1 "register_operand" "" ))) ]
  "" "" )
 
( define_insn ""
  [ ( set ( cc0 )
          ( compare ( match_operand:SZ 0 "register_operand" "D,D" )
                    ( match_operand:SZ 1
                               "register_or_immediate_operand" "SD,i" ))) ]
  ""
  "*return output_compare ( insn, operands );" "CCS_SET_CORRECTLY" )

;;
;;  ...........................................................................
;;
;;          TESTS
;;
;;  ...........................................................................
;;

( define_insn "tstpsi"
  [ ( set ( cc0 )
	  ( match_operand:PSI 0 "register_operand" "D" )) ]
  ""
  "*
{
    if ( CC_UNSIGNED == ( cc_status.mdep = next_cc_use ( insn )))
    {
	return \"move	#0,%k0\;\"
	       \"tst	%0\";
    }
    else
    {
	return \"tst	%0\";
    }
}" )

( define_insn "tstsi"
  [ ( set ( cc0 )
	  ( match_operand:SI 0 "register_operand" "D" )) ]
  ""
  "*return output_tst ( insn, operands );" )

( define_insn "tstdi"
  [ ( set ( cc0 )
	  ( match_operand:DI 0 "general_operand" "D" )) ]
  ""
  "*return output_tst ( insn, operands );" )

;;
;;  ...........................................................................
;;
;;          SCALAR CONVERSIONS USING TRUNCATION
;;
;;  ...........................................................................
;;

( define_insn "truncsipsi2"
  [ ( set ( match_operand:PSI 0 "register_operand" "=A,A" )
	  ( truncate:PSI ( match_operand:SI 1 "register_operand" "=S,D" ))) ]
  ""
  "move	%e1,%0" )

( define_insn "truncdisi2"
  [ ( set ( match_operand:SI 0 "general_operand" "=S,S,D,D" )
	  ( truncate:SI ( match_operand:DI 1 "general_operand" "S,D,S,D" ))) ]
  ""
  "*
{
    if ( DSP_B_REGNUM >= REGNO ( operands[1] ))
    {
	return \"move	%h1,%0\";
    }
    else
    {
	return \"move	%g1,%0\";
    }
}")

( define_insn "truncdzsz2"
  [ ( set ( match_operand:SZ 0 "general_operand" "=S,D" )
          ( truncate:SZ ( match_operand:DZ 1 "general_operand" "S,D" ))) ]
  "TARGET_C_FOR_DSP"
  "move %1,%0  ; from truncdzsz2" "CCS_NOT_AFFECTED" )

;;
;;  ...........................................................................
;;
;;          SCALAR CONVERSIONS USING ZERO EXTENSION
;;
;;  ...........................................................................
;;

( define_expand "zero_extendqisi2"
  [ ( set ( match_operand:SI 0 "register_operand" "" )
	  ( zero_extend:SI ( match_operand:QI 1 "register_operand" "" ))) ]
  ""
  "
{
    if ( SUBREG == GET_CODE ( operands[1] ))
    {
	operands[1] = copy_rtx ( SUBREG_REG ( operands[1] ));
    }
    else
    {
	operands[1] = copy_rtx ( operands[1] );
    }	
    operands[1] = gen_rtx ( SUBREG, SImode, operands[1], 0 );
    
    emit_insn ( gen_rtx ( SET, VOIDmode, operands[0], operands[1] ));

    DONE;
}" )

( define_insn "zero_extendpsisi2"
  [ ( set ( match_operand:SI 0 "general_operand" "=S,D" )
	  ( zero_extend:SI ( match_operand:PSI 1 "general_operand" "r,r" ))) ]
  ""
  "*
{
    /* we may want to add mem-ref as an opt. later. */

    if ( REGNO ( operands[0] ) == REGNO ( operands[1] ))
    {
	return \"\";
    }
    
    return \"move	%1,%0\";
}")

( define_insn "zero_extendsidi2"
  [ ( set ( match_operand:DI 0 "general_operand" "=&S,&S,&D,&D" )
	  ( zero_extend:DI 
	   ( match_operand:SI 1 "general_operand" "S,D,S,D" ))) ]
  ""
  "*
{
    if ( DST_REGS == REGNO_REG_CLASS ( REGNO ( operands[0] )))
    {
        return \"clr	%0\;\"
	       \"move	%1,%h0\";
    }
    else
    {
	return \"move	%e1,%0\;\"
	       \"move	#0,%g0\";
    }
}")

;;
;;  ...........................................................................
;;
;;          SCALAR CONVERSIONS USING SIGN EXTENSION
;;
;;  ...........................................................................
;;

( define_expand "extendqisi2"
  [ ( set ( match_operand:SI 0 "register_operand" "" )
	  ( sign_extend:SI ( match_operand:QI 1 "register_operand" "" ))) ]
  ""
  "
{
    if ( SUBREG == GET_CODE ( operands[1] ))
    {
	operands[1] = copy_rtx ( SUBREG_REG ( operands[1] ));
    }
    else
    {
	operands[1] = copy_rtx ( operands[1] );
    }
    operands[1] = gen_rtx ( SUBREG, SImode, operands[1], 0 );
    
    emit_insn ( gen_rtx ( SET, VOIDmode, operands[0], operands[1] ));

    DONE;
}" )

( define_insn "extendsidi2"
  [ ( set ( match_operand:DI 0 "general_operand" "=S" )
	  ( sign_extend:DI ( match_operand:SI 1 "general_operand" "D" ))) ]
  ""
  "move	%e1,%0\;move	%k1,%g0" )

( define_insn "extendpsisi2"
  [ ( set ( match_operand:SI 0 "general_operand" "=D,D" )
	  ( sign_extend:SI ( match_operand:PSI 1 "general_operand" "A,S" ))) ]
  ""
  "*
{
    /* we may want to add mem-ref as an opt. later. */

    if ( DST_REGS == REGNO_REG_CLASS ( REGNO ( operands[0] )) &&
	ADDR_REGS != REGNO_REG_CLASS ( REGNO ( operands[1] )) &&
	! MEM_IN_STRUCT_P ( operands[0] ) &&
	! MEM_IN_STRUCT_P ( operands[1] ))
    {
	return \"tfr	%1,%0\";
    }
    else
    {
	return \"move	%1,%0\";
    }
}")

( define_insn "extendszdz2"
  [ ( set ( match_operand:DZ 0 "general_operand" "=S" )
          ( sign_extend:DZ ( match_operand:SZ 1 "general_operand" "D" ))) ]
  "TARGET_C_FOR_DSP"
  "move %1,%0\;move     #0,%g0  ;  from extendszdz2" "CCS_NOT_AFFECTED" )

( define_insn "extenddzxz2"
  [ ( set ( match_operand:XDZ 0 "general_operand" "=S" )
          ( sign_extend:XDZ ( match_operand:DZ 1 "general_operand" "D" ))) ]
  "TARGET_C_FOR_DSP"
  "move %1,%0\;move     #0,%g0  ;  from extenddzxz2" "CCS_NOT_AFFECTED" )

;;
;;  ...........................................................................
;;
;;          CONVERSIONS BETWEEN FLOAT AND DOUBLE
;;
;;  ...........................................................................
;;

;;
;;  ...........................................................................
;;
;;          CONVERSIONS BETWEEN FLOATING POINT AND INTEGER
;;
;;  ...........................................................................
;;

 ;; Using the signed routine at this point - this is a bug.

( define_insn "floatunssidf2"
  [ ( set ( match_operand:DF 0 "register_operand" "=D" )
	  ( unsigned_float:DF ( match_operand:SI 1 "register_operand" "0" ))) ]
  ""
  "jsr	floatsidf_%0" )

 ;; Using the signed routine at this point - this is a bug.

( define_insn "floatunssisf2"
  [ ( set ( match_operand:SF 0 "register_operand" "=D" )
	  ( unsigned_float:SF ( match_operand:SI 1 "register_operand" "0" ))) ]
  ""
  "jsr	floatsidf_%0" )

( define_insn "floatsidf2"
  [ ( set ( match_operand:DF 0 "register_operand" "=D" )
	  ( float:DF ( match_operand:SI 1 "register_operand" "0" ))) ]
  ""
  "jsr	floatsidf_%0" )
	
( define_insn "floatsisf2"
  [ ( set ( match_operand:SF 0 "register_operand" "=D" )
	  ( float:SF ( match_operand:SI 1 "register_operand" "0" ))) ]
  ""
  "jsr	floatsidf_%0" )

( define_insn "fixdfsi2"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( fix:SI ( match_operand:DF 1 "register_operand" "0" ))) ]
  ""
  "jsr	fixdfsi_%0" )

( define_insn "fixsfsi2"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( fix:SI ( match_operand:SF 1 "register_operand" "0" ))) ]
  ""
  "jsr	fixdfsi_%0" )

( define_insn "fixunsdfsi2"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( unsigned_fix:SI ( match_operand:DF 1 "register_operand" "0" ))) ]
  ""
  "jsr	fixunsdfsi_%0" )

( define_insn "fixunssfsi2"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( unsigned_fix:SI ( match_operand:SF 1 "register_operand" "0" ))) ]
  ""
  "jsr	fixunsdfsi_%0" )

 ;; Using the signed routine at this point - this is a bug.

( define_insn "floatunsdidf2"
  [ ( set ( match_operand:DF 0 "register_operand" "=D" )
	  ( unsigned_float:DF ( match_operand:DI 1 "register_operand" "0" ))) ]
  ""
  "jsr	floatdidf_%0" )

 ;; Using the signed routine at this point - this is a bug.

( define_insn "floatunsdisf2"
  [ ( set ( match_operand:SF 0 "register_operand" "=D" )
	  ( unsigned_float:SF ( match_operand:DI 1 "register_operand" "0" ))) ]
  ""
  "jsr	floatdidf_%0" )

( define_insn "floatdidf2"
  [ ( set ( match_operand:DF 0 "register_operand" "=D" )
	  ( float:DF ( match_operand:DI 1 "register_operand" "0" ))) ]
  ""
  "jsr	floatdidf_%0" )
	
( define_insn "floatdisf2"
  [ ( set ( match_operand:SF 0 "register_operand" "=D" )
	  ( float:SF ( match_operand:DI 1 "register_operand" "0" ))) ]
  ""
  "jsr	floatdidf_%0" )

( define_insn "fixdfdi2"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( fix:DI ( match_operand:DF 1 "register_operand" "0" ))) ]
  ""
  "jsr	fixdfdi_%0" )

( define_insn "fixsfdi2"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( fix:DI ( match_operand:SF 1 "register_operand" "0" ))) ]
  ""
  "jsr	fixdfdi_%0" )

( define_insn "fixunsdfdi2"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( unsigned_fix:DI ( match_operand:DF 1 "register_operand" "0" ))) ]
  ""
  "jsr	fixunsdfdi_%0" )

( define_insn "fixunssfdi2"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( unsigned_fix:DI ( match_operand:SF 1 "register_operand" "0" ))) ]
  ""
  "jsr	fixunsdfdi_%0" )

( define_expand "fix_truncdfsi2"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( fix:SI ( match_operand:DF 1 "register_operand" "0" ))) ]
  ""
  "" )

( define_expand "fix_truncsfsi2"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( fix:SI ( match_operand:SF 1 "register_operand" "0" ))) ]
  ""
  "" )

( define_expand "fixuns_truncdfsi2"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( unsigned_fix:SI ( match_operand:DF 1 "register_operand" "0" ))) ]
  ""
  "" )

( define_expand "fixuns_truncsfsi2"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( unsigned_fix:SI ( match_operand:SF 1 "register_operand" "0" ))) ]
  ""
  "" )

( define_expand "fix_truncdfdi2"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( fix:DI ( match_operand:DF 1 "register_operand" "0" ))) ]
  ""
  "" )

( define_expand "fix_truncsfdi2"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( fix:DI ( match_operand:SF 1 "register_operand" "0" ))) ]
  ""
  "" )

( define_expand "fixuns_truncdfdi2"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( unsigned_fix:DI ( match_operand:DF 1 "register_operand" "0" ))) ]
  ""
  "" )

( define_expand "fixuns_truncsfdi2"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( unsigned_fix:DI ( match_operand:SF 1 "register_operand" "0" ))) ]
  ""
  "" )


;;  ...........................................................................
;;          CONVERSIONS BETWEEN FLOATING POINT AND FRAC
 
( define_insn "fracsfsz2"
  [ ( set ( match_operand:SZ 0 "register_operand" "=D" )
          ( frac:SZ ( match_operand:SF 1 "register_operand" "0" ))) ]
  "TARGET_C_FOR_DSP"
  "jsr fracsfsz_%0" "CCS_SET_CORRECTLY | BSR_LAST_OP" )
 
( define_insn "fracsfdz2"
  [ ( set ( match_operand:DZ 0 "register_operand" "=D" )
          ( frac:DZ ( match_operand:SF 1 "register_operand" "0" ))) ]
  "TARGET_C_FOR_DSP"
  "jsr fracsfdz_%0" "CCS_SET_CORRECTLY | BSR_LAST_OP" )
 
( define_insn "fracdfsz2"
  [ ( set ( match_operand:SZ 0 "register_operand" "=D" )
          ( frac:SZ ( match_operand:DF 1 "register_operand" "0" ))) ]
  "TARGET_C_FOR_DSP"
  "jsr fracdfsz_%0" "CCS_SET_CORRECTLY | BSR_LAST_OP" )
 
( define_insn "fracdfdz2"
  [ ( set ( match_operand:DZ 0 "register_operand" "=D" )
          ( frac:DZ ( match_operand:DF 1 "register_operand" "0" ))) ]
  "TARGET_C_FOR_DSP"
  "jsr fracdfdz_%0" "CCS_SET_CORRECTLY | BSR_LAST_OP" )
 
 
( define_insn "floatszsf2"
  [ ( set ( match_operand:SF 0 "register_operand" "=D" )
          ( float:SF ( match_operand:SZ 1 "register_operand" "0" ))) ]
  "TARGET_C_FOR_DSP"
  "jsr floatszsf_%0" "CCS_SET_CORRECTLY | BSR_LAST_OP" )
 
( define_insn "floatdzsf2"
  [ ( set ( match_operand:SF 0 "register_operand" "=D" )
          ( float:SF ( match_operand:DZ 1 "register_operand" "0" ))) ]
  "TARGET_C_FOR_DSP"
  "jsr floatdzsf_%0" "CCS_SET_CORRECTLY | BSR_LAST_OP" )
 
( define_insn "floatszdf2"
  [ ( set ( match_operand:DF 0 "register_operand" "=D" )
          ( float:DF ( match_operand:SZ 1 "register_operand" "0" ))) ]
  "TARGET_C_FOR_DSP"
  "jsr floatszdf_%0" "CCS_SET_CORRECTLY | BSR_LAST_OP" )
 
( define_insn "floatdzdf2"
  [ ( set ( match_operand:DF 0 "register_operand" "=D" )
          ( float:DF ( match_operand:DZ 1 "register_operand" "0" ))) ]
  "TARGET_C_FOR_DSP"
  "jsr floatdzdf_%0" "CCS_SET_CORRECTLY | BSR_LAST_OP" )
 

;;  ...........................................................................
;;          CONVERSIONS FROM INTEGERS TO FRACS
( define_expand "fracsisz2"
  [ ( set ( match_operand:SZ 0 "register_operand" "=D" )
          ( frac:SZ ( match_operand:SI 1 "register_operand" "0" ))) ]
  ""
  "" )
 
( define_insn ""
  [ ( set ( match_operand:SZ 0 "register_operand" "=D" )
          ( frac:SZ ( match_operand:SI 1 "register_operand" "0" ))) ]
  "TARGET_C_FOR_DSP"
  "; SI->SZ" "CCS_SET_CORRECTLY" )
 
;; Shot in the dark...
( define_expand "truncszsi2"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
          ( truncate:SI ( match_operand:SZ 1 "register_operand" "0" ))) ]
  ""
  "" )
 
( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
          ( truncate:SI ( match_operand:SZ 1 "register_operand" "0" ))) ]
  "TARGET_C_FOR_DSP"
  "; SZ->SI" "CCS_SET_CORRECTLY" )
 
;;
;;  ...........................................................................
;;
;;          CONDITIONAL JUMPS
;;
;;  ...........................................................................
;;

( define_insn "do"
  [ ( parallel
      [ ( clobber ( cc0 ))
	( use ( match_operand:SI 0 "general_operand" "J,S,D" ))
	( set ( pc ) ( if_then_else ( eq ( cc0 ) ( const_int 0 ))
				    ( label_ref ( match_operand 1 "" "" ))
				    ( pc ))) ] ) ]
  ""
  "*return output_do ( insn, operands );" )

;; This shape should match the back-branch insn and produce no real code.
;; It is a placeholder so that the compiler knows that the do loop target
;; label is implicitly a branch.

( define_insn "od"
  [ ( parallel 
      [ ( clobber ( cc0 ))
	( set ( pc ) ( match_operand 0 "" "" )) ] ) ]
  ""
  "*return output_od ( insn, operands );" )

( define_insn ""
  [ ( parallel [ ( set ( match_operand:SI 0 "register_operand" "=D,D,D" )
		       ( match_operand:SI 1 "general_operand" "i,!S,D" ))
		 ( clobber 
		   ( match_operand:SI 2 "register_operand" "=S,S,S" ))
		 ] ) ]
  ""
  "*
{
    if ( ! which_alternative )
    {
	if ( 0 == INTVAL ( operands[1] ))
	{
	    return \"clr	%0\";
	}
	else
	{
	    return \"move	#>1,%0\";
	}
    }

    if ( DST_REGS == REGNO_REG_CLASS ( REGNO ( operands[1] )))
    {
	return \"move	%e1,%0\";
    }
    else
    {
	return \"move	%1,%0\";
    }
}" )

( 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_expand "bgt"
  [ ( set ( pc ) ( if_then_else ( gt ( 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 "blt"
  [ ( set ( pc ) ( if_then_else ( lt ( cc0 ) ( const_int 0 ))
				( label_ref ( match_operand 0 "" "" ))
				( pc ))) ] "" "" )
( define_expand "ble"
  [ ( set ( pc ) ( if_then_else ( le ( cc0 ) ( const_int 0 ))
				( label_ref ( match_operand 0 "" "" ))
				( pc ))) ] "" "" )
( define_expand "bequ"
  [ ( set ( pc ) ( if_then_else ( equ ( cc0 ) ( const_int 0 ))
				( label_ref ( match_operand 0 "" "" ))
				( pc ))) ] "" "" )
( define_expand "bneu"
  [ ( set ( pc ) ( if_then_else ( neu ( 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 "bgeu"
  [ ( set ( pc ) ( if_then_else ( geu ( 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 "bleu"
  [ ( set ( pc ) ( if_then_else ( leu ( cc0 ) ( const_int 0 ))
				( label_ref ( match_operand 0 "" "" ))
				( pc ))) ] "" "" )
( define_insn ""
  [ ( set ( pc )
	  ( if_then_else ( match_operator 1 "cond_operator"
					  [ ( cc0 ) ( const_int 0 ) ] )
			 ( label_ref ( match_operand 0 "" "" ))
			 ( pc ))) ]
  ""
  "j%1	%l0" )

( define_insn ""
  [ ( set ( pc )
	  ( if_then_else ( match_operator 1 "cond_operator"
					  [ ( cc0 ) ( const_int 0 ) ] )
			 ( pc )
			 ( label_ref ( match_operand 0 "" "" )))) ]
  ""
  "*
{ 
    PUT_CODE ( operands[1], reverse_condition ( GET_CODE ( operands[1] )));

    return \"j%1	%l0\";
}" )

;;  ...........................................................................
;;          CONDITIONAL 1/0 SETS

( define_expand "seq"
  [ ( parallel
      [ ( set ( match_operand:SI 0 "register_operand" "" )
	      ( eq ( cc0 ) ( const_int 0 )))
	( clobber ( match_operand:SI 1 "register_operand" "" )) ] ) ] 
  "" "{ operands[1] = gen_reg_rtx ( SImode ); }" )
    
( define_expand "sne"
  [ ( parallel
      [ ( set ( match_operand:SI 0 "register_operand" "" )
	      ( ne ( cc0 ) ( const_int 0 )))
	( clobber ( match_operand:SI 1 "register_operand" "" )) ] ) ] 
  "" "{ operands[1] = gen_reg_rtx ( SImode ); }" )
    
( define_expand "sgt"
  [ ( parallel
      [ ( set ( match_operand:SI 0 "register_operand" "" )
	      ( gt ( cc0 ) ( const_int 0 )))
	( clobber ( match_operand:SI 1 "register_operand" "" )) ] ) ] 
  "" "{ operands[1] = gen_reg_rtx ( SImode ); }" )
    
( define_expand "sge"
  [ ( parallel
      [ ( set ( match_operand:SI 0 "register_operand" "" )
	      ( ge ( cc0 ) ( const_int 0 )))
	( clobber ( match_operand:SI 1 "register_operand" "" )) ] ) ] 
  "" "{ operands[1] = gen_reg_rtx ( SImode ); }" )
    
( define_expand "slt"
  [ ( parallel
      [ ( set ( match_operand:SI 0 "register_operand" "" )
	      ( lt ( cc0 ) ( const_int 0 )))
	( clobber ( match_operand:SI 1 "register_operand" "" )) ] ) ] 
  "" "{ operands[1] = gen_reg_rtx ( SImode ); }" )
    
( define_expand "sle"
  [ ( parallel
      [ ( set ( match_operand:SI 0 "register_operand" "" )
	      ( le ( cc0 ) ( const_int 0 )))
	( clobber ( match_operand:SI 1 "register_operand" "" )) ] ) ] 
  "" "{ operands[1] = gen_reg_rtx ( SImode ); }" )
    
( define_expand "sequ"
  [ ( parallel
      [ ( set ( match_operand:SI 0 "register_operand" "" )
	      ( equ ( cc0 ) ( const_int 0 )))
	( clobber ( match_operand:SI 1 "register_operand" "" )) ] ) ] 
  "" "{ operands[1] = gen_reg_rtx ( SImode ); }" )
    
( define_expand "sneu"
  [ ( parallel
      [ ( set ( match_operand:SI 0 "register_operand" "" )
	      ( neu ( cc0 ) ( const_int 0 )))
	( clobber ( match_operand:SI 1 "register_operand" "" )) ] ) ] 
  "" "{ operands[1] = gen_reg_rtx ( SImode ); }" )
    
( define_expand "sgtu"
  [ ( parallel
      [ ( set ( match_operand:SI 0 "register_operand" "" )
	      ( gtu ( cc0 ) ( const_int 0 )))
	( clobber ( match_operand:SI 1 "register_operand" "" )) ] ) ] 
  "" "{ operands[1] = gen_reg_rtx ( SImode ); }" )
    
( define_expand "sgeu"
  [ ( parallel
      [ ( set ( match_operand:SI 0 "register_operand" "" )
	      ( geu ( cc0 ) ( const_int 0 )))
	( clobber ( match_operand:SI 1 "register_operand" "" )) ] ) ] 
  "" "{ operands[1] = gen_reg_rtx ( SImode ); }" )
    
( define_expand "sltu"
  [ ( parallel
      [ ( set ( match_operand:SI 0 "register_operand" "" )
	      ( ltu ( cc0 ) ( const_int 0 )))
	( clobber ( match_operand:SI 1 "register_operand" "" )) ] ) ] 
  "" "{ operands[1] = gen_reg_rtx ( SImode ); }" )
    
( define_expand "sleu"
  [ ( parallel
      [ ( set ( match_operand:SI 0 "register_operand" "" )
	      ( leu ( cc0 ) ( const_int 0 )))
	( clobber ( match_operand:SI 1 "register_operand" "" )) ] ) ] 
  "" "{ operands[1] = gen_reg_rtx ( SImode ); }" )
    
( define_insn ""
  [ ( parallel 
      [ ( set ( match_operand:SI 0 "register_operand" "=D,D" )
	      ( match_operator 2 "cond_operator" [ ( cc0 ) ( const_int 0 ) ] ))
	( clobber ( match_operand:SI 1 "register_operand" "=S,D" )) ] ) ]
  ""
  "move	#>1,%1\;move	#0,%0\;t%2	%1,%0" )

;; when the optimizer grinds on a conditional 1/0 set, either of the 
;; following two INSNs can be left hanging around. 

( define_insn ""
  [ ( parallel
      [ ( set ( match_operand:SI 0 "register_operand" "=r" )
	      ( match_operand:SI 1 "immediate_operand" "i"))
	( clobber ( match_operand:SI 2 "general_operand" "=mr" )) ] ) ]
  "" "*{ which_alternative = 3; return move_single_integer ( operands ); }" )

;;
;;  ...........................................................................
;;
;;          UNCONDITIONAL JUMP
;;
;;  ...........................................................................
;;

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


;;
;;  ...........................................................................
;;
;;          TABLE JUMP ( SWITCH IMPLEMENTATION )
;;
;;  ...........................................................................
;;

( define_insn "tablejump"
  [ ( parallel [ ( set ( pc ) ( match_operand:PSI 0 "memory_operand" "m" ))
		 ( clobber ( match_operand:PSI 1 "register_operand" "=A" ))
		 ( use ( label_ref ( match_operand 2 "" "" ))) ] ) ]
  ""
  "*
{
    if ( TARGET_P_MEM_SWITCHTABLE )
    {
	return \"move	p:%f0,%1\;\"
	       \"jmp	(%1)\";
    }
    else
    {
	return \"move	%0,%1\;\"
	       \"jmp	(%1)\";
    }
}" )

;;
;;  ...........................................................................
;;
;;          SUBROUTINE CALLS
;;
;;  ...........................................................................
;;

( define_insn "call"
  [ ( call ( match_operand:PSI 0 "register_or_restricted_memory_operand" "mA" )
	   ( match_operand:SI 1 "immediate_operand" "i" )) ]
  ""
  "*
{
    clear_n_reg_values ( );
    
    switch ( INTVAL ( operands[1] ))
    {
    case 0:
	return \"jsr	%f0\";
	
    case 1:
	return \"jsr	%f0\;\"
	       \"move	(r6)-\";
	
    case 2:
	return \"jsr	%f0\;\"
	       \"move	(r6)-\;\"
	       \"move	(r6)-\";
	
    default:
	return \"jsr	%f0\;\"
	       \"move	#%p1,n6\;\"
	       \"move	(r6)-n6\";
    }
}" )

( define_insn "call_value"
  [ ( set
      ( match_operand 0 "" "" )
      ( call 
	( match_operand:PSI 1 "register_or_restricted_memory_operand" "mA" )
	( match_operand:SI 2 "immediate_operand" "i" ))) ]
  ""
  "*
{
    clear_n_reg_values ( );
    
    switch ( INTVAL ( operands[2] ))
    {
    case 0:
	return \"jsr	%f1\";
	
    case 1:
	return \"jsr	%f1\;\"
	       \"move	(r6)-\";
	
    case 2:
	return \"jsr	%f1\;\"
	       \"move	(r6)-\;\"
	       \"move	(r6)-\";
	
    default:
	return \"jsr	%f1\;\"
	       \"move	#%p2,n6\;\"
	       \"move	(r6)-n6\";
    }
}" )


;;
;;  ...........................................................................
;;
;;          NOP
;;
;;  ...........................................................................
;;

( define_insn "nop"
  [ ( const_int 0 ) ]
  ""
  "*
{
    rtx peek = PREV_INSN ( insn );
    
    while (( peek ) && 
	   (( NOTE == GET_CODE ( peek )) ||
	    (( JUMP_INSN == GET_CODE ( peek )) &&
	     ( PARALLEL == GET_CODE ( PATTERN ( peek ))))))
    {
	peek = PREV_INSN ( peek );
    }
    if (( ! peek ) || ( CODE_LABEL != GET_CODE ( peek )) ||
	( ! LABEL_NUSES ( peek )))
    {
	return \"\";
    }
    
    peek = NEXT_INSN ( insn );
    while (( peek ) && 
	   (( NOTE == GET_CODE ( peek )) ||
	    (( JUMP_INSN == GET_CODE ( peek )) &&
	     ( PARALLEL == GET_CODE ( PATTERN ( peek ))))))
    {
	peek = NEXT_INSN ( peek );
    }
    if (( ! peek ) || 
	( ! LABEL_NUSES ( peek )) ||
	(( CODE_LABEL != GET_CODE ( peek )) && 
	 ( const0_rtx != PATTERN ( peek ))))
    {
	return \"\";
    }

    return \"nop\";
}" )

;; This insn is needed because jump.c doesn't realize that this is really
;; a nop.

( define_insn "" [ ( set ( pc ) ( pc )) ] "" "" )

( define_insn "probe" 
  [ ( parallel [ ( const_int 0 ) ] ) ]
  ""
  "*
{
    if ( TARGET_STACK_CHECK )
    {
	return \"jsr	F__stack_check\";
    }
    else
    {
	return \"\";
    }
}" )

;; these are single bit set, clear and extract instructions.

( define_expand "bitset"
  [ ( set 
      ( match_operand:SI 0 "register_or_restricted_memory_operand" "" )
      ( bitset:SI
	( match_dup 0 )
	( match_operand:SI 1 "immediate_operand" "" ))) ]
  ""
  "" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "restricted_memory_operand" "+m" )
	  ( bitset:SI ( match_dup 0 )
		      ( match_operand:SI 1 "immediate_operand" "i" ))) ]
  "restricted_memref_p ( operands[0] )"
  "bset	#%1,%0" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=r" )
	  ( bitset:SI ( match_operand:SI 1 "register_operand" "0" )
		      ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  ""
  "bset	#%2,%e0" )

( define_insn ""
  [ ( set ( match_operand:DI 0 "restricted_memory_operand" "+m" )
	  ( bitset:DI ( match_dup 0 )
		      ( match_operand:SI 1 "immediate_operand" "i" ))) ]
  "restricted_memref_p ( operands[0] )"
  "*return output_long_mem_bitop ( \"*set\", operands );" )

( define_insn ""
  [ ( set ( match_operand:DI 0 "register_operand" "=S,D" )
	  ( bitset:DI ( match_operand:DI 1 "register_operand" "0,0" )
		      ( match_operand:SI 2 "immediate_operand" "i,i" ))) ]
  ""
  "*return output_long_reg_bitop ( \"*set\", operands );" )

( define_expand "bitclr"
  [ ( set
      ( match_operand:SI 0 "register_or_restricted_memory_operand" "" )
      ( bitclr:SI 
	( match_dup 0 )
	( match_operand:SI 1 "immediate_operand" "" ))) ]
 "" "" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "restricted_memory_operand" "+m" )
	  ( bitclr:SI ( match_dup 0 )
		      ( match_operand:SI 1 "immediate_operand" "i" ))) ]
  "restricted_memref_p ( operands[0] )"
  "bclr	#%1,%0" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=r" )
	  ( bitclr:SI ( match_operand:SI 1 "register_operand" "0" )
		      ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  ""
  "bclr	#%2,%0" )

( define_insn ""
  [ ( set ( match_operand:DI 0 "restricted_memory_operand" "+m" )
	  ( bitclr:DI ( match_dup 0 )
		      ( match_operand:SI 1 "immediate_operand" "i" ))) ]
  "restricted_memref_p ( operands[0] )"
  "*return output_long_mem_bitop ( \"*clr\", operands );" )

( define_insn ""
  [ ( set ( match_operand:DI 0 "register_operand" "=S,D" )
	  ( bitclr:DI ( match_operand:DI 1 "register_operand" "0,0" )
		      ( match_operand:SI 2 "immediate_operand" "i,i" ))) ]
  ""
  "*return output_long_reg_bitop ( \"*clr\", operands );" )

( define_expand "bitchg"
  [ ( set
      ( match_operand:SI 0 "register_or_restricted_memory_operand" "" )
      ( bitchg:SI 
	( match_dup 0 )
	( match_operand:SI 1 "immediate_operand" "" ))) ]
 "" "" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "restricted_memory_operand" "+m" )
	  ( bitchg:SI ( match_dup 0 )
		      ( match_operand:SI 1 "immediate_operand" "i" ))) ]
  "restricted_memref_p ( operands[0] )"
  "bchg	#%1,%0" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=r" )
	  ( bitchg:SI ( match_operand:SI 1 "register_operand" "0" )
		      ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  ""
  "bchg	#%2,%0" )

( define_insn ""
  [ ( set ( match_operand:DI 0 "restricted_memory_operand" "+m" )
	  ( bitchg:DI ( match_dup 0 )
		      ( match_operand:SI 1 "immediate_operand" "i" ))) ]
  "restricted_memref_p ( operands[0] )"
  "*return output_long_mem_bitop ( \"*chg\", operands );" )

( define_insn ""
  [ ( set ( match_operand:DI 0 "register_operand" "=S,D" )
	  ( bitchg:DI ( match_operand:DI 1 "register_operand" "0,0" )
		      ( match_operand:SI 2 "immediate_operand" "i,i" ))) ]
  ""
  "*return output_long_reg_bitop ( \"*chg\", operands );" )

;;
;;  ...........................................................................
;;
;;          PEEPHOLE OPTIMIZATIONS
;;
;;  ...........................................................................
;;

;; this sequence can be introduced by the do loop generation code. a 
;; reasonable data flow analysis and optimization phase will (in the future)
;; clean it up.

( define_peephole 
  [ ( set ( match_operand:SI 0 "register_operand" "=D,D" )
	  ( minus:SI ( match_operand:SI 1 "register_operand" "0,0" )
		     ( match_operand:SI 2 "register_operand" "S,D" )))
    ( set ( match_dup 0 )
	  ( plus:SI ( match_dup 1 )
		    ( match_dup 2 ))) ]
  "( ! rtx_equal_p (operands[0], operands[2] ))" 
  "" )


;; ...........................................................................
;; jscc/bscc peepholers. these take advantage of some cases where 
;; conditional branches jump around function calls.

( define_peephole
  [ ( set ( pc )
	  ( if_then_else
	    ( match_operator 1 "cond_operator" [ ( cc0 ) ( const_int 0 ) ] )
	    ( pc ) ( label_ref ( match_operand 2 "" "" ))))
    ( parallel [ ( call ( match_operand:PSI 0 "general_operand" "mA" )
			( const_int 0 )) ] ) ]
  "jscc_combo_follows_p ( insn, operands[2] )"
  "*return output_jscc ( insn, operands, FALSE );" )

( define_peephole
  [ ( set ( pc )
	  ( if_then_else
	    ( match_operator 1 "cond_operator" [ ( cc0 ) ( const_int 0 ) ] )
	    ( label_ref ( match_operand 2 "" "" )) ( pc )))
    ( parallel [ ( call ( match_operand:PSI 0 "general_operand" "mA" )
			( const_int 0 )) ] ) ]
  "jscc_combo_follows_p ( insn, operands[2] )"
  "*return output_jscc ( insn, operands, TRUE );" )

( define_peephole
  [ ( set ( pc )
	  ( if_then_else
	    ( match_operator 1 "cond_operator" [ ( cc0 ) ( const_int 0 ) ] )
	    ( pc ) ( label_ref ( match_operand 2 "" "" ))))
    ( parallel 
      [ ( set ( match_operand 3 "" "" )
	      ( call ( match_operand:PSI 0 "general_operand" "mA" )
		     ( const_int 0 ))) ] ) ]
  "jscc_combo_follows_p ( insn, operands[2] )"
  "*return output_jscc ( insn, operands, FALSE );" )

( define_peephole
  [ ( set ( pc )
	  ( if_then_else
	    ( match_operator 1 "cond_operator" [ ( cc0 ) ( const_int 0 ) ] )
	    ( label_ref ( match_operand 2 "" "" )) ( pc )))
    ( parallel 
      [ ( set ( match_operand 3 "" "" )
	      ( call ( match_operand:PSI 0 "general_operand" "mA" )
		     ( const_int 0 ))) ] ) ]
  "jscc_combo_follows_p ( insn, operands[2] )"
  "*return output_jscc ( insn, operands, TRUE );" )


;; ...........................................................................
;; js(clr/set)/bs(clr/set) peepholers. these take advantage of some cases
;; where conditional branches jump around function calls.

( define_peephole
  [ ( set 
      ( pc )
      ( if_then_else
	( ne
	  ( sign_extract
	    ( match_operand:SI 1 "register_or_restricted_memory_operand" "" )
	    ( const_int 1 )
	    ( match_operand:SI 2 "immediate_operand" "" ))
	  ( const_int 0 ))
	( pc ) ( label_ref ( match_operand 3 "" "" ))))
    ( parallel [ ( call ( match_operand:PSI 0 "general_operand" "" )
			( const_int 0 )) ] ) ]
  "jscc_combo_follows_p ( insn, operands[3] )"
  "*return output_jsbit ( insn, operands, TRUE );" )

( define_peephole
  [ ( set 
      ( pc )
      ( if_then_else
	( eq
	  ( sign_extract
	    ( match_operand:SI 1 "register_or_restricted_memory_operand" "" )
	    ( const_int 1 )
	    ( match_operand:SI 2 "immediate_operand" "" ))
	  ( const_int 0 ))
	( pc ) ( label_ref ( match_operand 3 "" "" ))))
    ( parallel [ ( call ( match_operand:PSI 0 "general_operand" "" )
			( const_int 0 )) ] ) ]
  "jscc_combo_follows_p ( insn, operands[3] )"
  "*return output_jsbit ( insn, operands, FALSE );" )

( define_peephole
  [ ( set 
      ( pc )
      ( if_then_else
	( ne
	  ( sign_extract
	    ( match_operand:SI 1 "register_or_restricted_memory_operand" "" )
	    ( const_int 1 )
	    ( match_operand:SI 2 "immediate_operand" "" ))
	  ( const_int 0 ))
	( label_ref ( match_operand 3 "" "" )) ( pc )))
    ( parallel [ ( call ( match_operand:PSI 0 "general_operand" "" )
			( const_int 0 )) ] ) ]
  "jscc_combo_follows_p ( insn, operands[3] )"
  "*return output_jsbit ( insn, operands, FALSE );" )

( define_peephole
  [ ( set 
      ( pc )
      ( if_then_else
	( eq
	  ( sign_extract
	    ( match_operand:SI 1 "register_or_restricted_memory_operand" "" )
	    ( const_int 1 )
	    ( match_operand:SI 2 "immediate_operand" "" ))
	  ( const_int 0 ))
	( label_ref ( match_operand 3 "" "" )) ( pc )))
    ( parallel [ ( call ( match_operand:PSI 0 "general_operand" "" )
			( const_int 0 )) ] ) ]
  "jscc_combo_follows_p ( insn, operands[3] )"
  "*return output_jsbit ( insn, operands, TRUE );" )

;;- Local variables:
;;- mode:emacs-lisp
;;- comment-start: ";;- "
;;- eval: ( set-syntax-table ( copy-sequence ( syntax-table )))
;;- eval: ( modify-syntax-entry ?[ "(]" )
;;- eval: ( modify-syntax-entry ?] ")[" )
;;- eval: ( modify-syntax-entry ?{ "(}" )
;;- eval: ( modify-syntax-entry ?} "){" )
;;- End:

