;;- Machine description for the Motorola dsp561XX 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: 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.

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

( 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 "register_operand" "=r,<>m,r,r" )
	  ( match_operand:QI 1 "general_operand" "r,r,<>m,i" )) ]
  ""
  "*{ return move_singleword ( operands ); }" "1" )

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

( 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 "register_operand" "=r,<>m,r,r" )
	  ( match_operand:SI 1 "general_operand" "r,r,<>m,i" )) ]
  ""
  "*{ return move_singleword ( operands ); }" "1" )

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

( 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 "register_operand" "=DQ,<>m,DQ,DQ" )
	  ( match_operand:DI 1 "general_operand" "DQ,DQ,<>m,Gi" )) ]
  ""
  "*{ return move_doubleword ( 0, operands ); }" "1" )

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

( 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 "register_operand" "=DQ,<>m,DQ,DQ" )
	  ( match_operand:SF 1 "general_operand" "DQ,DQ,<>m,G" )) ]
  ""
  "*{ return move_doubleword ( 1, operands ); }" "1" )

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

( 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 "register_operand" "=DQ,<>m,DQ,DQ" )
	  ( match_operand:DF 1 "general_operand" "DQ,DQ,<>m,G" )) ]
  ""
  "*{ return move_doubleword ( 1, operands ); }" "1" )

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

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

( define_expand "movstrsi"
  [ ( parallel [ ( set ( match_operand:BLK 0 "" "" )
		       ( match_operand:BLK 1 "" "" ))
		 ( use ( match_operand:SI 2 "" "" )) ] ) ]
  ""
  "
{
    /* we want to force both addresses into registers so that the rtl 
       generated by this define_expand will be matched by the following 
       define_insn. */

    operands[0] = copy_rtx ( operands[0] );
    XEXP ( operands[0], 0 ) = force_reg ( Pmode, XEXP ( operands[0], 0 ));

    operands[1] = copy_rtx ( operands[1] );
    XEXP ( operands[1], 0 ) = force_reg ( Pmode, XEXP ( operands[1], 0 ));
}" )

( define_insn ""
  [ ( parallel
      [ ( set ( mem:BLK ( match_operand:SI 0 "register_operand" "A" ))
	      ( mem:BLK ( match_operand:SI 1 "register_operand" "A" )))
	( use ( match_operand:SI 2 "immediate_operand" "i" )) ] ) ]
  ""
  "*
{
    switch ( INTVAL ( operands[2] ))
    {
    case 1:
	return \"move	x:(%1),%j1\;\"
	       \"move	%j1,x:(%0)\";

    case 2:
	return \"move	x:(%1)+,%j1\;\"
	       \"move	%j1,x:(%0)+\;\"
	       \"move	x:(%1)-,%j1\;\"
	       \"move	%j1,x:(%0)-\";

    case 3:
	if ( !TARGET_CONSERVE_P_MEM )
	{	
            return \"move	x:(%1)+,%j1\;\"
                   \"move	%j1,x:(%0)+\;\"
                   \"move	x:(%1)+,%j1\;\"
                   \"move	%j1,x:(%0)+\;\"
                   \"move	x:(%1)-,%j1\;\"
                   \"move	%j1,x:(%0)-\;\"
                   \"move	(%1)-\;\"
                   \"move	(%0)-\";
        }
    default:
	operands[3] = gen_label_rtx ( );
    
	return \"do	#%q2,%l3\;\"
	       \"move	x:(%1)+,%j1\;\"
	       \"move	%j1,x:(%0)+\;\"
               \"\\n%l3\;\"
               \"move	#-(%q2),%j1\;\"
               \"move	#-(%q2),%j0\;\"
               \"move	(%1)+%j1\;\"
               \"move	(%0)+%j0\";
    }
}" )

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

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=r" )
	  ( plus:SI ( match_operand:SI 1 "register_operand" "r" )
		    ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  "STACK_POINTER_REGNUM == REGNO ( operands[1] ) ||
   FRAME_POINTER_REGNUM == REGNO ( operands[1] )"
  "*
{
    clear_n_reg_values ( );
    
    return \"move	#%q2,%j1\;\"
           \"lea	(%1)+%j1,%j1\;\"
	   \"move	%j1,%0\";
}" )    

;; this next trick won't work if the offset from r2 is too big. we need
;; an even more stinky kludge for that.

( define_insn ""
  [ ( set ( match_operand:SI 0 "memory_operand" "=m" )
	  ( plus:SI ( match_operand:SI 1 "register_operand" "r" )
		    ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  "STACK_POINTER_REGNUM == REGNO ( operands[1] ) ||
   FRAME_POINTER_REGNUM == REGNO ( operands[1] )"
  "*
{
    static char conglom[BUFSIZ];
    char *mod_spot;
    
    operands[5] = operands[2];
    clear_n_reg_values ( );
    strcpy ( conglom, \"move	#%q5,%j1\;\"
		      \"lea	(%1)+%j1,%j1\;\" );
    which_alternative = 1;
    strcat ( conglom, move_singleword ( operands ));
    * ( mod_spot = strrchr ( conglom, ',' ) - 1 ) = '2';
    * ( -- mod_spot ) = 'n';
    * ( -- mod_spot ) = '\\t';
    * ( mod_spot - 1 ) = ' ';
    
    return conglom;
}" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=R" )
	  ( plus:SI ( match_operand:SI 1 "register_operand" "0" )
		    ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  "1 == INTVAL ( operands[2] )"
  "*{ return ( DSP_B_REGNUM < REGNO ( operands[0] )) ?
 \"lea	(%0)+,%0\" : \"inc24	%0\"; }" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=R" )
	  ( plus:SI ( match_operand:SI 1 "register_operand" "0" )
		    ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  "2 == INTVAL ( operands[2] )"
  "*{ return ( DSP_B_REGNUM < REGNO ( operands[0] )) ?

 \"lea	(%0)+,%0\;\"
 \"lea	(%0)+,%0\" :

 \"inc24	%0\;\"
 \"inc24	%0\"; }" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=R" )
	  ( plus:SI ( match_operand:SI 1 "register_operand" "0" )
		    ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  "-1 == INTVAL ( operands[2] ) || 0xffff == INTVAL ( operands[2] )"
  "*{ return ( DSP_B_REGNUM < REGNO ( operands[0] )) ?
 \"move	(%0)-\" : \"dec24	%0\"; }" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=R" )
	  ( plus:SI ( match_operand:SI 1 "register_operand" "0" )
		    ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  "-2 == INTVAL ( operands[2] ) || 0xfffe == INTVAL ( operands[2] )"
  "*{ return ( DSP_B_REGNUM < REGNO ( operands[0] )) ?

 \"move	(%0)-\;\"
 \"move	(%0)-\" :

 \"dec24	%0\;\"
 \"dec24	%0\"; }" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=A" )
	  ( plus:SI ( match_operand:SI 1 "register_operand" "0" )
		    ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  ""
  "move	#%q2,%j0\;move	(%0)+%j0" )

( 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" "D,Q" ))) ]
  ""
  "*
{
    return ( REGNO ( operands[2] ) == REGNO ( operands[1] )) ?
	\"asl	%0\;\"
	\"ext	%0\" :

	\"add	%2,%0\";
}" )

( define_insn ""
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( plus:DI ( match_operand:DI 1 "register_operand" "0" )
		    ( match_operand:DI 2 "immediate_operand" "i" ))) ]
  "1 == INTVAL ( operands[2] )"
  "inc	%0" )

( define_insn ""
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( plus:DI ( match_operand:DI 1 "register_operand" "0" )
		    ( match_operand:DI 2 "immediate_operand" "i" ))) ]
  "-1 == INTVAL ( operands[2] )"
  "dec	%0" )

( define_insn "adddi3"
  [ ( 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" "D,Q" ))) ]
  ""
  "*
{
    return ( REGNO ( operands[2] ) == REGNO ( operands[1] )) ?

	\"asl	%0\;\"
	\"ext	%0\" :

	\"add	%i2,%0\";
}" )

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

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

;; this define_insn needs to come before all other adds, as the stack adjusts
;; will need to match it specifically.

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=r" )
	  ( minus:SI ( match_operand:SI 1 "register_operand" "0" )
		     ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  "STACK_POINTER_REGNUM == REGNO ( operands[0] )"
  "*
{
    if ( CONST_INT == GET_CODE ( operands[2] ))
    {
	switch ( INTVAL ( operands[2] ))
	{
	case 0:
	    return \"\";
	    
	case 1:
	    return \"move	(%0)-\";
	    
	case 2:
	    return \"move	(%0)-\;\"
	           \"move	(%0)-\";
	    
	case 3:
	    return \"move	(%0)-\;\"
	           \"move	(%0)-\;\"
		   \"move	(%0)-\";
	}
    }
    return \"move	#-(%q2),%j0\;\"
           \"move	(%0)+%j0\";
}" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=R" )
	  ( minus:SI ( match_operand:SI 1 "register_operand" "0" )
		     ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  "1 == INTVAL ( operands[2] )"
  "*{ return ( DSP_B_REGNUM < REGNO ( operands[0] )) ?
 \"move	(%0)-\" : \"dec24	%0\"; }" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=R" )
	  ( minus:SI ( match_operand:SI 1 "register_operand" "0" )
		     ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  "2 == INTVAL ( operands[2] )"
  "*{ return ( DSP_B_REGNUM < REGNO ( operands[0] )) ?

 \"move	(%0)-\;\"
 \"move	(%0)-\" :

 \"dec24	%0\;\"
 \"dec24	%0\"; }" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=R" )
	  ( minus:SI ( match_operand:SI 1 "register_operand" "0" )
		     ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  "-1 == INTVAL ( operands[2] ) || 0xffff == INTVAL ( operands[2] )"
  "*{ return ( DSP_B_REGNUM < REGNO ( operands[0] )) ?
 \"lea	(%0)+,%0\" : \"inc24	%0\"; }" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=R" )
	  ( minus:SI ( match_operand:SI 1 "register_operand" "0" )
		     ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  "-2 == INTVAL ( operands[2] ) || 0xfffe == INTVAL ( operands[2] )"
  "*{ return ( DSP_B_REGNUM < REGNO ( operands[0] )) ?

 \"lea	(%0)+,%0\;\"
 \"lea	(%0)+,%0\" :

 \"inc24	%0\;\"
 \"inc24	%0\"; }" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=A" )
	  ( minus:SI ( match_operand:SI 1 "register_operand" "0" )
		     ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  ""
  "move	#-(%q2),%j0\;move	(%0)+%j0" )

( 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,Q" ))) ]
  ""
  "*
{ 
    return ( REGNO ( operands[1] ) == REGNO ( operands[2] )) ? 
	\"clr	%0\" : \"sub	%2,%0\";
}" )

( define_insn ""
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( minus:DI ( match_operand:DI 1 "register_operand" "0" )
		     ( match_operand:DI 2 "immediate_operand" "i" ))) ]
  "1 == INTVAL ( operands[2] )"
  "dec	%0" )

( define_insn ""
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( minus:DI ( match_operand:DI 1 "register_operand" "0" )
		     ( match_operand:DI 2 "immediate_operand" "i" ))) ]
  "-1 == INTVAL ( operands[2] )"
  "inc	%0" )

( define_insn "subdi3"
  [ ( 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" "D,Q" ))) ]
  ""
  "*
{ 
    return ( REGNO ( operands[1] ) == REGNO ( operands[2] )) ? 
	\"clr	%0\" : \"sub	%i2,%0\";
}" )

( define_insn "subdf3"
  [ ( set ( match_operand:DF 0 "general_operand" "=D,D" )
          ( minus:DF ( match_operand:DF 1 "general_operand" "0,0" )
                     ( match_operand:DF 2 "general_operand" "D,Q" ))) ]
  ""
  "bsr	fsub_%i2%0" )

;;
;;  ...........................................................................
;;
;;          MULTIPLICATIONS 
;;
;;  ...........................................................................
;;

;; We have two shapes for mac+ and two shapes for mac-, because the mult may
;; turn up as either operand of the plus/minus. we allow either signed or 
;; unsigned multiply to be specified; it doesn't matter.

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D,D" )
	  ( plus:SI ( match_operand:SI 1 "register_operand" "0,0" )
		    ( match_operator:SI
		      2 "multiply_operator" 
		      [ ( match_operand:SI 3 "register_operand" "%x,q" )
			( match_operand:SI 4 "register_operand" "T,t" ) ] ))) ]
  ""
  "imac	%3,%4,%0" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D,D" )
	  ( plus:SI ( match_operator:SI
		      1 "multiply_operator"
		      [ ( match_operand:SI 2 "register_operand" "%x,q" )
			( match_operand:SI 3 "register_operand" "T,t" ) ] )
		    ( match_operand:SI 4 "register_operand" "0,0" ))) ]
  ""
  "imac	%2,%3,%0" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D,D" )
	  ( minus:SI ( match_operand:SI 1 "register_operand" "0,0" )
		     ( mult:SI ( match_operand:SI 2 "register_operand" "%x,q" )
			       ( match_operand:SI
				 3 "register_operand" "T,t" )))) ]
  ""
  "neg	%0\;imac	%2,%3,%0\;neg	%0" )

( define_insn "mulsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "=D,D" )
	  ( mult:SI ( match_operand:SI 1 "register_operand" "%x,q" )
		    ( match_operand:SI 2 "register_operand" "T,t" ))) ]
  ""
  "impy	%2,%1,%0" )

( define_insn "umulsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "=D,D" )
	  ( umult:SI ( match_operand:SI 1 "register_operand" "%x,q" )
		     ( match_operand:SI 2 "register_operand" "T,t" ))) ]
  ""
  "impy	%2,%1,%0" )

( define_insn ""
  [ ( set ( match_operand:DI 0 "register_operand" "=D,D" )
          ( mult:DI ( match_operand:DI 1 "register_operand" "%x,y" )
		    ( match_operand:DI 2 "register_operand" "y,x" ))) ]
  "TARGET_CONSERVE_P_MEM"
  "bsr	lmpy_%i1%i2%0" )

( define_insn "muldi3"
  [ ( set ( match_operand:DI 0 "register_operand" "=D,D" )
          ( mult:DI ( match_operand:DI 1 "register_operand" "%x,y" )
		    ( match_operand:DI 2 "register_operand" "y,x" ))) ]
  ""
  "mpysu	%g1,%2,%0\;macsu	%g2,%1,%0\;asr	%0\;move	%h0,%0\;asl	%0\;macuu	%1,%2,%0\;asr	%0\;ext	%0" )

( define_insn ""
  [ ( set ( match_operand:DI 0 "register_operand" "=D,D" )
          ( umult:DI ( match_operand:DI 1 "register_operand" "%x,y" )
		     ( match_operand:DI 2 "register_operand" "y,x" ))) ]
  "TARGET_CONSERVE_P_MEM"
  "bsr	ulmpy_%i1%i2%0" )

( define_insn "umuldi3"
  [ ( set ( match_operand:DI 0 "register_operand" "=D,D" )
          ( umult:DI ( match_operand:DI 1 "register_operand" "%x,y" )
		     ( match_operand:DI 2 "register_operand" "y,x" ))) ]
  ""
  "mpyuu	%g1,%2,%0\;macuu	%g2,%1,%0\;asr	%0\;move	%h0,%0\;asl	%0\;macuu	%1,%2,%0\;asr	%0" )

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

;;
;;  ...........................................................................
;;
;;          DIVISIONS
;;
;;  ...........................................................................
;;

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( div:SI ( match_operand:SI 1 "register_operand" "0" )
		   ( match_operand:SI 2 "register_operand" "Q" ))) ]
  "TARGET_CONSERVE_P_MEM"
  "bsr	idiv_%2%0" )

( define_insn "divsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( div:SI ( match_operand:SI 1 "register_operand" "0" )
		   ( match_operand:SI 2 "register_operand" "Q" ))) ]
  ""
  "*
{
    if ( TARGET_REP )
    {
	operands[3] = gen_label_rtx ( );
	operands[4] = gen_label_rtx ( );
    
	return
	    \"andi	#$00,ccr\;\"
	    \"eor	%2,%0\;\"
            \"bmi	<%l3\;\"
            \"ori	#$80,ccr\"
\"\\n%l3\;\"
            \"eor	%2,%0\;\"
            \"abs	%0\;\"
            \"asr16	%0\;\"
            \"asl	%0\;\"
            \"rep	#$10\;\"
            \"div	%2,%0\;\"
            \"move	%h0,%0\;\"
            \"bftstl	#$0080,sr\;\"
            \"bcc	<%l4\;\"
            \"neg	%0\"
\"\\n%l4\";
    }
    else
    {
	operands[3] = gen_label_rtx ( );
	operands[4] = gen_label_rtx ( );
	operands[5] = gen_label_rtx ( );
    
	return
	    \"andi	#$00,ccr\;\"
	    \"eor	%2,%0\;\"
            \"bmi	<%l3\;\"
            \"ori	#$80,ccr\"
\"\\n%l3\;\"
            \"eor	%2,%0\;\"
            \"abs	%0\;\"
            \"asr16	%0\;\"
            \"asl	%0\;\"
            \"do	#$10,%l5\;\"
            \"div	%2,%0\"
\"\\n%l5\;\"
            \"move	%h0,%0\;\"
            \"bftstl	#$0080,sr\;\"
            \"bcc	<%l4\;\"
            \"neg	%0\"
\"\\n%l4\";
    }
}" )

( 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" ))) ]
  ""
  "*
{
    if ( REGNO ( operands[2] ) == REGNO ( operands[0] ))
    {
	return \"move	#>1,%0\";
    }
    else
    {
	return \"bsr	udiv_%2%0\";
    }
}" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( mod:SI ( match_operand:SI 1 "register_operand" "0" )
		   ( match_operand:SI 2 "register_operand" "Q" ))) ]
  "TARGET_CONSERVE_P_MEM"
  "bsr	imod_%2%0" )

( define_insn "modsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( mod:SI ( match_operand:SI 1 "register_operand" "0" )
		   ( match_operand:SI 2 "register_operand" "Q" ))) ]
  ""
  "*
{
    if ( TARGET_REP )
    {
	operands[3] = gen_label_rtx ( );
	operands[4] = gen_label_rtx ( );
	operands[6] = gen_label_rtx ( );
	operands[7] = gen_label_rtx ( );
    
	return
	    \"andi	#$00,ccr\;\"
	    \"tst	%0\;\"
            \"bmi	<%l3\;\"
            \"ori	#$80,ccr\"
\"\\n%l3\;\"
            \"abs	%0\;\"
            \"asr16	%0\;\"
            \"asl	%0\;\"
            \"rep	#$10\;\"
            \"div	%2,%0\;\"
            \"move	%e0,%0\;\"
	    \"tst	%2\;\"
	    \"bmi	<%l7\;\"
	    \"add	%2,%0\;\"
	    \"bra	<%l6\"
\"\\n%l7\;\"
	    \"sub	%2,%0\"
\"\\n%l6\;\"
	    \"asr	%0\;\"
            \"bftstl	#$0080,sr\;\"
            \"bcc	<%l4\;\"
            \"neg	%0\"
\"\\n%l4\";
    }
    else
    {
	operands[3] = gen_label_rtx ( );
	operands[4] = gen_label_rtx ( );
	operands[5] = gen_label_rtx ( );
	operands[6] = gen_label_rtx ( );
	operands[7] = gen_label_rtx ( );
    
	return
	    \"andi	#$00,ccr\;\"
	    \"tst	%0\;\"
            \"bmi	<%l3\;\"
            \"ori	#$80,ccr\"
\"\\n%l3\;\"
            \"abs	%0\;\"
            \"asr16	%0\;\"
            \"asl	%0\;\"
            \"do	#$10,%l5\;\"
            \"div	%2,%0\"
\"\\n%l5\;\"
            \"move	%e0,%0\;\"
	    \"tst	%2\;\"
	    \"bmi	<%l7\;\"
	    \"add	%2,%0\;\"
	    \"bra	<%l6\"
\"\\n%l7\;\"
	    \"sub	%2,%0\"
\"\\n%l6\;\"
	    \"asr	%0\;\"
            \"bftstl	#$0080,sr\;\"
            \"bcc	<%l4\;\"
            \"neg	%0\"
\"\\n%l4\";
    }
}" )

( 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" ))) ]
  ""
  "*
{
    if ( REGNO ( operands[2] ) == REGNO ( operands[0] ))
    {
	return \"clr	%0\";
    }
    else
    {
	return \"bsr	umod_%2%0\";
    }
}" )

( 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" "Q" ))) ]
  ""
  "bsr	ldiv_%m2%0" )

( define_insn "udivdi3"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
          ( udiv:DI ( match_operand:DI 1 "register_operand" "0" )
		    ( match_operand:DI 2 "register_operand" "Q" ))) ]
  ""
  "bsr	uldiv_%m2%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" "Q" ))) ]
  ""
  "bsr	lmod_%m2%0" )

( define_insn "divdf3"
  [ ( set ( match_operand:DF 0 "general_operand" "=D,D" )
          ( div:DF ( match_operand:DF 1 "general_operand" "0,0" )
                   ( match_operand:DF 2 "general_operand" "D,Q" ))) ]
  ""
  "bsr	fdiv_%i2%0" )

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

( 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 "negdf2"
  [ ( set ( match_operand:DF 0 "general_operand" "=D,Q" )
          ( neg:DF ( match_operand:DF 1 "general_operand" "0,0" ))) ]
  ""
  "*{ return ( which_alternative ) ? 

 \"bfchg	#$8000,%t0\" :

 \"bfchg	#$8000,%t0\;\"
 \"ext	%0\"; }" )

;;
;;  ...........................................................................
;;
;;          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" )

( define_insn "absdf2"
  [ ( set ( match_operand:DF 0 "general_operand" "=D,Q" )
          ( abs:DF ( match_operand:DF 1 "general_operand" "0,0" ))) ]
  ""
  "*{ return ( which_alternative ) ? 

 \"bfclr	#$8000,%t0\" :

 \"bfclr	#$8000,%t0\;\"
 \"zero	%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" "Q" ))) ]
  ""
  "and	%2,%0\;ext	%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" "Q" ))) ]
  ""
  "and	%g2,%0\;swap	%0\;and	%2,%0\;swap	%0\;ext	%0" )

;;
;;  ...........................................................................
;;
;;          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" "Q" ))) ]
  ""
  "or	%2,%0\;ext	%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" "Q" ))) ]
  ""
  "or	%g2,%0\;swap	%0\;or	%2,%0\;swap	%0\;ext	%0" )

;;
;;  ...........................................................................
;;
;;          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" "Q" ))) ]
  ""
  "eor	%2,%0\;ext	%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" "Q" ))) ]
  ""
  "eor	%g2,%0\;swap	%0\;eor	%2,%0\;swap	%0\;ext	%0" )

;;
;;  ...........................................................................
;;
;;          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\;ext	%0" )

( define_insn "one_cmpldi2"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( not:DI ( match_operand:DI 1 "register_operand" "0" ))) ]
  ""
  "neg	%0\;dec	%0" )

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

( define_expand "ashlsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "" )
	  ( ashift:SI 
	    ( match_operand:SI 1 "register_operand" "" )
	    ( match_operand:SI 2 "register_or_immediate_operand" "" ))) ]
  ""
  "" )

( 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" ))) ]
  ""
  "*
{
    int count = INTVAL ( operands[2] ), this_pass;
    static char retstr[ sizeof ( \"asl4	%0\" ) * BITS_PER_UNIT + 1 ];

    retstr[0] = '\\0';
    if ( 0 < count && BITS_PER_UNIT > count )
    {
	do
	{
	    this_pass = ( count & 3 ) ? ( count & 3 ) : 4;
	
	    switch ( this_pass )
	    {
	    case 1:
		strcat ( retstr, \"asl	%0\;\" );
		break;
		
	    case 2:
		strcat ( retstr, \"asl	%0\;\"
				 \"asl	%0\;\" );
		break;
		
	    case 3:
		strcat ( retstr, \"asl4	%0\;\"
				 \"asr	%0\;\" );
		break;

	    case 4:
		strcat ( retstr, \"asl4	%0\;\" );
	    }
	}
	while ( count -= this_pass );
	
	strcat ( retstr, \"ext	%0\" );

	return retstr;
    }
    return \"clr	%0\";
}" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D,D,D" )
	  ( ashift:SI ( match_operand:SI 1 "register_operand" "y,t,t" )
		      ( match_operand:SI 2 "register_operand" "X,X,T" ))) ]
  "TARGET_LP16"
  "shfl	%e1,%2,%0" )

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

( define_expand "ashrsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( ashiftrt:SI 
	    ( match_operand:SI 1 "register_operand" "" )
	    ( match_operand:SI 2 "register_or_immediate_operand" "" ))) ]
  ""
  "" )

( 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" ))) ]
  ""
  "*
{
    int count = INTVAL ( operands[2] ), this_pass;
    static char retstr[ sizeof ( \"asr4	%0\" ) * BITS_PER_UNIT + 1 ];

    retstr[0] = '\\0';
    if ( 0 < count && BITS_PER_UNIT > count )
    {
	do
	{
	    this_pass = ( count & 3 ) ? ( count & 3 ) : 4;
	
	    switch ( this_pass )
	    {
	    case 1:
		strcat ( retstr, \"asr	%0\;\" );
		break;
		
	    case 2:
		strcat ( retstr, \"asr	%0\;\"
				 \"asr	%0\;\" );
		break;
		
	    case 3:
		strcat ( retstr, \"asl	%0\;\"
				 \"asr4	%0\;\" );
		break;

	    case 4:
		strcat ( retstr, \"asr4	%0\;\" );
	    }
	}
	while ( count -= this_pass );
	
	/* because this is an SImode operation, we need to clear the
	   bottom of the accumulator. */
	strcat ( retstr, \"move	%e0,%0\" );

	return retstr;
    }
    return \"clr	%0\";
}" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=D,D,D" )
	  ( ashiftrt:SI ( match_operand:SI 1 "register_operand" "y,t,t" )
			( match_operand:SI 2 "register_operand" "X,X,T" ))) ]
  "TARGET_LP16"
  "shfr	%e1,%2,%0\;move	#>0,%h0" )

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

( 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" ))) ]
  ""
  "*
{
    int count = INTVAL ( operands[2] ), this_pass;
    static char retstr[ sizeof ( \"asl4	%0\" ) * LONG_TYPE_SIZE + 1 ];

    retstr[0] = '\\0';
    if ( 16 < count )
    {
	strcat ( retstr, \"move	%h0,%0\" );
	count -= 16;
    
	if ( count )
	{
	    strcat ( retstr, \"\;\" );
	}
    }
    
    if ( 0 < count && LONG_TYPE_SIZE > count )
    {
	do
	{
	    this_pass = ( count & 3 ) ? ( count & 3 ) : 4;
	
	    switch ( this_pass )
	    {
	    case 1:
		strcat ( retstr, \"asl	%0\;\" );
		break;
		
	    case 2:
		strcat ( retstr, \"asl	%0\;\"
			         \"asl	%0\;\" );
		break;
		
	    case 3:
		strcat ( retstr, \"asl4	%0\;\"
			         \"asr	%0\;\" );
		break;

	    case 4:
		strcat ( retstr, \"asl4	%0\;\" );
	    }
	}
	while ( count -= this_pass );
	
	strcat ( retstr, \"ext	%0\" );

	return retstr;
    }
    return \"clr	%0\";
}" )

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

( 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" ))) ]
  ""
  "*
{
    int count = INTVAL ( operands[2] ), this_pass;
    static char retstr[ sizeof ( \"asr	%0\" ) * LONG_TYPE_SIZE + 1 ];

    retstr[0] = '\\0';
    if ( 0 < count && LONG_TYPE_SIZE > count )
    {
	do
	{
	    this_pass = ( count & 0xf ) ? ( count & 0xf ) : 16;
	
	    switch ( this_pass )
	    {
	    case 1:
		strcat ( retstr, \"asr	%0\" );
		break;
		
	    case 2:
		strcat ( retstr, \"asr	%0\;\"
			         \"asr	%0\" );
		break;
		
	    case 3:
		strcat ( retstr, \"asl	%0\;\"
			         \"asr4	%0\" );
		break;

	    case 4:
		strcat ( retstr, \"asr4	%0\" );
		break;
		
	    case 5:
		strcat ( retstr, \"asr4	%0\;\"
			         \"asr	%0\" );
		break;
		
	    case 6:
		strcat ( retstr, \"asr4	%0\;\"
			         \"asr	%0\;\"
			         \"asr	%0\" );
		break;
		
	    case 7:
		strcat ( retstr, \"asr4	%0\;\"
			         \"asl	%0\;\"
			         \"asr4	%0\" );
		break;

	    case 8:
		strcat ( retstr, \"asr4	%0\;\"
			         \"asr4	%0\" );
		break;
		
	    case 9:
		strcat ( retstr, \"asr4	%0\;\"
			         \"asr	%0\;\"
			         \"asr4	%0\" );
		break;
		
	    case 10:
		strcat ( retstr, \"asr4	%0\;\"
			         \"asr	%0\;\"
			         \"asr	%0\;\"
			         \"asr4	%0\" );
		break;
		
	    case 11:
		strcat ( retstr, \"asl4	%0\;\"
			         \"asl	%0\;\"
			         \"asr16	%0\" );
		break;
		
	    case 12:
		strcat ( retstr, \"asl4	%0\;\"
			         \"asr16	%0\" );
		break;
		
	    case 13:
		strcat ( retstr, \"asl4	%0\;\"
			         \"asr	%0\;\"
			         \"asr16	%0\" );
		break;
		
	    case 14:
		strcat ( retstr, \"asl	%0\;\"
			         \"asl	%0\;\"
			         \"asr16	%0\" );
		break;
		
	    case 15:
		strcat ( retstr, \"asl	%0\;\"
			         \"asr16	%0\" );
		break;
		
	    case 16:
		strcat ( retstr, \"asr16	%0\" );
	    }

	    if ( count > 16 )
	    {
		strcat ( retstr, \"\;\" );
	    }
	}
	while ( count -= this_pass );
	
	return retstr;
    }
    return \"clr	%0\";
}" )

( define_insn "ashrdi3"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( ashiftrt:DI ( match_operand:DI 1 "register_operand" "0" )
			( match_operand:SI 2 "register_operand" "DQ" ))) ]
  ""
  "*
{
    operands[3] = gen_label_rtx ( );
    
    if ( TARGET_REP )
    {
	return \"tst	%2\;\"
	       \"ble	<%l3\;\"
	       \"rep	%2\;\"
	       \"asr	%0\"
	    \"\\n%l3\";
    }
    else
    {
	return \"tst	%2\;\"
	       \"ble	<%l3\;\"
	       \"do	%2,%l3\;\"
	       \"asr	%0\"
	    \"\\n%l3\";
    }
}" )

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

( define_insn "lshlsi3"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( lshift:SI ( match_operand:SI 1 "register_operand" "0" )
		      ( match_operand:SI 2 "register_operand" "DQ" ))) ]
  ""
  "*
{
    operands[3] = gen_label_rtx ( );
    
    if ( TARGET_REP )
    {
	return \"tst	%2\;\"
	       \"ble	<%l3\;\"
	       \"rep	%2\;\"
	       \"lsl	%0\"
	    \"\\n%l3\;\"
	       \"ext	%0\";
    }
    else
    {
	return \"tst	%2\;\"
	       \"ble	<%l3\;\"
	       \"do	%2,%l3\;\"
	       \"lsl	%0\"
	    \"\\n%l3\;\"
	       \"ext	%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 "register_operand" "DQ" ))) ]
  ""
  "*
{
    operands[3] = gen_label_rtx ( );
    
    if ( TARGET_REP )
    {
	return \"tst	%2\;\"
	       \"ble	<%l3\;\"
	       \"zero	%0\;\"
	       \"rep	%2\;\"
	       \"lsr	%0\"
	    \"\\n%l3\;\"
	       \"move	%e0,%0\";
    }
    else
    {
	return \"tst	%2\;\"
	       \"ble	<%l3\;\"
	       \"zero	%0\;\"
	       \"do	%2,%l3\;\"
	       \"asr	%0\"
	    \"\\n%l3\;\"
	       \"move	%e0,%0\";
    }
}" )

( define_insn "lshldi3"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( lshift:DI ( match_operand:DI 1 "register_operand" "0" )
		      ( match_operand:SI 2 "register_operand" "DQ" ))) ]
  ""
  "*
{
    operands[3] = gen_label_rtx ( );
    
    if ( TARGET_REP )
    {
	return \"tst	%2\;\"
	       \"ble	<%l3\;\"
	       \"rep	%2\;\"
	       \"asl	%0\"
	    \"\\n%l3\;\"
	       \"ext	%0\";
    }
    else
    {
	return \"tst	%2\;\"
	       \"ble	<%l3\;\"
	       \"do	%2,%l3\;\"
	       \"asl	%0\"
	    \"\\n%l3\;\"
	       \"ext	%0\";
    }
}" )

( define_insn "lshrdi3"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( lshiftrt:DI ( match_operand:DI 1 "register_operand" "0" )
			( match_operand:SI 2 "register_operand" "DQ" ))) ]
  ""
  "*
{
    operands[3] = gen_label_rtx ( );
    
    if ( TARGET_REP )
    {
	return \"tst	%2\;\"
	       \"ble	<%l3\;\"
	       \"zero	%0\;\"
	       \"rep	%2\;\"
	       \"asr	%0\"
	    \"\\n%l3\;\"
	       \"ext	%0\";
    }
    else
    {
	return \"tst	%2\;\"
	       \"ble	<%l3\;\"
	       \"zero	%0\;\"
	       \"do	%2,%l3\;\"
	       \"asr	%0\"
	    \"\\n%l3\;\"
	       \"ext	%0\";
    }
}" )

;;  ...........................................................................
;;
;;          ROTATIONS
;;
;;  ...........................................................................
;;
;; I don't think we need these either!
;;
;;  ...........................................................................
;;
;;          COMPARISONS
;;
;;  ...........................................................................
;;

( 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" )
                    ( match_operand:SI 1 "register_operand" "DQ" ))) ]
  ""
  "*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_insn "cmpdf"
  [ ( set ( cc0 )
          ( compare ( match_operand:DF 0 "register_operand" "D,D" )
                    ( match_operand:DF 1 "register_operand" "D,Q" ))) ]
  ""
  "*
{
    if ( REGNO ( operands[0] ) == REGNO ( operands[1] ))
    {
	return \"bfclr	#$00ff,sr\;\"
	       \"bfset	#$0004,sr\";
    }
    else
    {
	return \"bsr	fcmp_%i1%0\";
    }
}" )

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

( define_insn "tstsi"
  [ ( set ( cc0 ) ( match_operand:SI 0 "register_operand" "DQ" )) ]
  ""
  "*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 "truncdisi2"
  [ ( set ( match_operand:SI 0 "general_operand" "=D,D" )
	  ( truncate:SI ( match_operand:DI 1 "general_operand" "D,Q" ))) ]
  ""
  "*
{
    if ( IS_SRC_OR_MPY_P ( REGNO ( operands[1] )))
    {
	return \"move	%g1,%0\";
    }
    else
    {
	return \"move	%h1,%0\";
    }
}" )
	
;;
;;  ...........................................................................
;;
;;          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_extendsidi2"
  [ ( set ( match_operand:DI 0 "general_operand" "=&D,Q" )
	  ( zero_extend:DI ( match_operand:SI 1 "general_operand" "DQ,DQ" ))) ]
  ""
  "*
{
    if ( DST_REGS == REGNO_REG_CLASS ( REGNO ( operands[0] )))
    {
	return \"clr	%0\;\"
	       \"move	%1,%h0\";
    }
    else
    {
	return \"move	%1,%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" "=Q" )
	  ( sign_extend:DI ( match_operand:SI 1 "general_operand" "D" ))) ]
  ""
  "move	%1,%0\;move	%k1,%g0" )

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

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

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

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

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

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

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

( define_insn "fixunsdfdi2"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( unsigned_fix:DI ( match_operand:DF 1 "register_operand" "0" ))) ]
  ""
  "bsr	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 "fixuns_truncdfsi2"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( unsigned_fix:SI ( match_operand:DF 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 "fixuns_truncdfdi2"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( unsigned_fix:DI ( match_operand:DF 1 "register_operand" "0" ))) ]
  ""
  "" )

;;
;;  ...........................................................................
;;
;;          CONDITIONAL JUMPS
;;
;;  ...........................................................................
;;

( define_insn "do"
  [ ( parallel
      [ ( clobber ( cc0 ))
	( use ( match_operand:SI 0 "general_operand" "r,J" ))
	( 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" )
		       ( match_operand:SI 1 "general_operand" "i,!r" ))
		 ( clobber ( match_operand:SI 2 "register_operand" "=r,r" ))
		 ] ) ]
  ""
  "*
{
    switch ( which_alternative )
    {
    case 0:
	if ( 0 == INTVAL ( operands[1] ))
	{
	    return \"clr	%0\";
	}
	else
	{
	    return \"move	#>1,%0\";
	}
    case 1:
	if ( DST_REGS == REGNO_REG_CLASS ( REGNO ( operands[1] )))
	{
	    return \"move	%e1,%0\";
	}
	else
	{
	    return \"move	%1,%0\";
	}
    }
}" )

( define_expand "seq"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( eq ( cc0 ) ( const_int 0 ))) ]
  ""
  "
{
    rtx clobber_exp = gen_rtx ( CLOBBER, VOIDmode, gen_reg_rtx ( SImode ));
    rtx set_exp = gen_rtx ( SET, VOIDmode, operands[0],
			   gen_rtx ( EQ, VOIDmode, cc0_rtx, const0_rtx ));
        
    emit_insn ( gen_rtx ( PARALLEL, VOIDmode,
			 gen_rtvec ( 2, set_exp, clobber_exp )));
    DONE;
}" )
    
( define_insn ""
  [ ( parallel [ ( set ( match_operand:SI 0 "register_operand" "=&D" )
		       ( eq ( cc0 ) ( const_int 0 )))
		 ( clobber ( match_operand:SI 1 "register_operand" "=D" )) ] )
  ]
  ""
  "move	#>1,%1\;move	#0,%0\;teq	%1,%0" )

( define_insn "beq"
  [ ( set ( pc )
	  ( if_then_else ( eq ( cc0 )
			      ( const_int 0 ))
			 ( label_ref ( match_operand 0 "" "" ))
			 ( pc ))) ]
  ""
  "beq	%l0" )

( define_expand "sequ"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( equ ( cc0 ) ( const_int 0 ))) ]
  ""
  "
{
    rtx clobber_exp = gen_rtx ( CLOBBER, VOIDmode, gen_reg_rtx ( SImode ));
    rtx set_exp = gen_rtx ( SET, VOIDmode, operands[0],
			   gen_rtx ( EQU, VOIDmode, cc0_rtx, const0_rtx ));
        
    emit_insn ( gen_rtx ( PARALLEL, VOIDmode,
			 gen_rtvec ( 2, set_exp, clobber_exp )));
    DONE;
}" )
    
( define_insn ""
  [ ( parallel [ ( set ( match_operand:SI 0 "register_operand" "=&D" )
		       ( equ ( cc0 ) ( const_int 0 )))
		 ( clobber ( match_operand:SI 1 "register_operand" "=D" )) ] )
  ]
  ""
  "move	#>1,%1\;move	#0,%0\;teq	%1,%0" )

( define_insn "bequ"
  [ ( set ( pc )
	  ( if_then_else ( equ ( cc0 )
			      ( const_int 0 ))
			 ( label_ref ( match_operand 0 "" "" ))
			 ( pc ))) ]
  ""
  "beq	%l0" )

( define_expand "sne"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( ne ( cc0 ) ( const_int 0 ))) ]
  ""
  "
{
    rtx clobber_exp = gen_rtx ( CLOBBER, VOIDmode, gen_reg_rtx ( SImode ));
    rtx set_exp = gen_rtx ( SET, VOIDmode, operands[0],
			   gen_rtx ( NE, VOIDmode, cc0_rtx, const0_rtx ));
        
    emit_insn ( gen_rtx ( PARALLEL, VOIDmode,
			 gen_rtvec ( 2, set_exp, clobber_exp )));
    DONE;
}" )
    
( define_insn ""
  [ ( parallel [ ( set ( match_operand:SI 0 "register_operand" "=&D" )
		       ( ne ( cc0 ) ( const_int 0 )))
		 ( clobber ( match_operand:SI 1 "register_operand" "=D" )) ] )
  ]
  ""
  "move	#>1,%1\;move	#0,%0\;tne	%1,%0" )

( define_insn "bne"
  [ ( set ( pc )
	  ( if_then_else ( ne ( cc0 )
			      ( const_int 0 ))
			 ( label_ref ( match_operand 0 "" "" ))
			 ( pc ))) ]
  ""
  "bne	%l0" )

( define_expand "sneu"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( neu ( cc0 ) ( const_int 0 ))) ]
  ""
  "
{
    rtx clobber_exp = gen_rtx ( CLOBBER, VOIDmode, gen_reg_rtx ( SImode ));
    rtx set_exp = gen_rtx ( SET, VOIDmode, operands[0],
			   gen_rtx ( NEU, VOIDmode, cc0_rtx, const0_rtx ));
        
    emit_insn ( gen_rtx ( PARALLEL, VOIDmode,
			 gen_rtvec ( 2, set_exp, clobber_exp )));
    DONE;
}" )
    
( define_insn ""
  [ ( parallel [ ( set ( match_operand:SI 0 "register_operand" "=&D" )
		       ( neu ( cc0 ) ( const_int 0 )))
		 ( clobber ( match_operand:SI 1 "register_operand" "=D" )) ] )
  ]
  ""
  "move	#>1,%1\;move	#0,%0\;tne	%1,%0" )

( define_insn "bneu"
  [ ( set ( pc )
	  ( if_then_else ( neu ( cc0 )
			      ( const_int 0 ))
			 ( label_ref ( match_operand 0 "" "" ))
			 ( pc ))) ]
  ""
  "bne	%l0" )

( define_expand "sgt"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( gt ( cc0 ) ( const_int 0 ))) ]
  ""
  "
{
    rtx clobber_exp = gen_rtx ( CLOBBER, VOIDmode, gen_reg_rtx ( SImode ));
    rtx set_exp = gen_rtx ( SET, VOIDmode, operands[0],
			   gen_rtx ( GT, VOIDmode, cc0_rtx, const0_rtx ));
        
    emit_insn ( gen_rtx ( PARALLEL, VOIDmode,
			 gen_rtvec ( 2, set_exp, clobber_exp )));
    DONE;
}" )
    
( define_insn ""
  [ ( parallel [ ( set ( match_operand:SI 0 "register_operand" "=&D" )
		       ( gt ( cc0 ) ( const_int 0 )))
		 ( clobber ( match_operand:SI 1 "register_operand" "=D" )) ] )
  ]
  ""
  "move	#>1,%1\;move	#0,%0\;tgt	%1,%0" )

( define_insn "bgt"
  [ ( set ( pc )
	  ( if_then_else ( gt ( cc0 )
			      ( const_int 0 ))
			 ( label_ref ( match_operand 0 "" "" ))
			 ( pc ))) ]
  ""
  "bgt	%l0" )

( define_expand "sgtu"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( gtu ( cc0 ) ( const_int 0 ))) ]
  ""
  "
{
    rtx clobber_exp = gen_rtx ( CLOBBER, VOIDmode, gen_reg_rtx ( SImode ));
    rtx set_exp = gen_rtx ( SET, VOIDmode, operands[0],
			   gen_rtx ( GTU, VOIDmode, cc0_rtx, const0_rtx ));
        
    emit_insn ( gen_rtx ( PARALLEL, VOIDmode,
			 gen_rtvec ( 2, set_exp, clobber_exp )));
    DONE;
}" )
    
( define_insn ""
  [ ( parallel [ ( set ( match_operand:SI 0 "register_operand" "=&D" )
		       ( gtu ( cc0 ) ( const_int 0 )))
		 ( clobber ( match_operand:SI 1 "register_operand" "=D" )) ] )
  ]
  ""
  "move	#>1,%1\;move	#0,%0\;tgt	%1,%0" )

( define_insn "bgtu"
  [ ( set ( pc )
	  ( if_then_else ( gtu ( cc0 )
			       ( const_int 0 ))
			 ( label_ref ( match_operand 0 "" "" ))
			 ( pc ))) ]
  ""
  "bgt	%l0" )

( define_expand "slt"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( lt ( cc0 ) ( const_int 0 ))) ]
  ""
  "
{
    rtx clobber_exp = gen_rtx ( CLOBBER, VOIDmode, gen_reg_rtx ( SImode ));
    rtx set_exp = gen_rtx ( SET, VOIDmode, operands[0],
			   gen_rtx ( LT, VOIDmode, cc0_rtx, const0_rtx ));
        
    emit_insn ( gen_rtx ( PARALLEL, VOIDmode,
			 gen_rtvec ( 2, set_exp, clobber_exp )));
    DONE;
}" )
    
( define_insn ""
  [ ( parallel [ ( set ( match_operand:SI 0 "register_operand" "=&D" )
		       ( lt ( cc0 ) ( const_int 0 )))
		 ( clobber ( match_operand:SI 1 "register_operand" "=D" )) ] )
  ]
  ""
  "move	#>1,%1\;move	#0,%0\;tlt	%1,%0" )

( define_insn "blt"
  [ ( set ( pc )
	  ( if_then_else ( lt ( cc0 )
			      ( const_int 0 ))
			 ( label_ref ( match_operand 0 "" "" ))
			 ( pc ))) ]
  ""
  "blt	%l0" )

( define_expand "sltu"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( ltu ( cc0 ) ( const_int 0 ))) ]
  ""
  "
{
    rtx clobber_exp = gen_rtx ( CLOBBER, VOIDmode, gen_reg_rtx ( SImode ));
    rtx set_exp = gen_rtx ( SET, VOIDmode, operands[0],
			   gen_rtx ( LTU, VOIDmode, cc0_rtx, const0_rtx ));
        
    emit_insn ( gen_rtx ( PARALLEL, VOIDmode,
			 gen_rtvec ( 2, set_exp, clobber_exp )));
    DONE;
}" )
    
( define_insn ""
  [ ( parallel [ ( set ( match_operand:SI 0 "register_operand" "=&D" )
		       ( ltu ( cc0 ) ( const_int 0 )))
		 ( clobber ( match_operand:SI 1 "register_operand" "=D" )) ] )
  ]
  ""
  "move	#>1,%1\;move	#0,%0\;tlt	%1,%0" )

( define_insn "bltu"
  [ ( set ( pc )
	  ( if_then_else ( ltu ( cc0 )
			       ( const_int 0 ))
			 ( label_ref ( match_operand 0 "" "" ))
			 ( pc ))) ]
  ""
  "blt	%l0" )

( define_expand "sge"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( ge ( cc0 ) ( const_int 0 ))) ]
  ""
  "
{
    rtx clobber_exp = gen_rtx ( CLOBBER, VOIDmode, gen_reg_rtx ( SImode ));
    rtx set_exp = gen_rtx ( SET, VOIDmode, operands[0],
			   gen_rtx ( GE, VOIDmode, cc0_rtx, const0_rtx ));
        
    emit_insn ( gen_rtx ( PARALLEL, VOIDmode,
			 gen_rtvec ( 2, set_exp, clobber_exp )));
    DONE;
}" )
    
( define_insn ""
  [ ( parallel [ ( set ( match_operand:SI 0 "register_operand" "=&D" )
		       ( ge ( cc0 ) ( const_int 0 )))
		 ( clobber ( match_operand:SI 1 "register_operand" "=D" )) ] )
  ]
  ""
  "move	#>1,%1\;move	#0,%0\;tge	%1,%0" )

( define_insn "bge"
  [ ( set ( pc )
	  ( if_then_else ( ge ( cc0 )
			      ( const_int 0 ))
			 ( label_ref ( match_operand 0 "" "" ))
			 ( pc ))) ]
  ""
  "bge	%l0" )

( define_expand "sgeu"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( geu ( cc0 ) ( const_int 0 ))) ]
  ""
  "
{
    rtx clobber_exp = gen_rtx ( CLOBBER, VOIDmode, gen_reg_rtx ( SImode ));
    rtx set_exp = gen_rtx ( SET, VOIDmode, operands[0],
			   gen_rtx ( GEU, VOIDmode, cc0_rtx, const0_rtx ));
        
    emit_insn ( gen_rtx ( PARALLEL, VOIDmode,
			 gen_rtvec ( 2, set_exp, clobber_exp )));
    DONE;
}" )
    
( define_insn ""
  [ ( parallel [ ( set ( match_operand:SI 0 "register_operand" "=&D" )
		       ( geu ( cc0 ) ( const_int 0 )))
		 ( clobber ( match_operand:SI 1 "register_operand" "=D" )) ] )
  ]
  ""
  "move	#>1,%1\;move	#0,%0\;tge	%1,%0" )

( define_insn "bgeu"
  [ ( set ( pc )
	  ( if_then_else ( geu ( cc0 )
			       ( const_int 0 ))
			 ( label_ref ( match_operand 0 "" "" ))
			 ( pc ))) ]
  ""
  "bge	%l0" )

( define_expand "sle"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( le ( cc0 ) ( const_int 0 ))) ]
  ""
  "
{
    rtx clobber_exp = gen_rtx ( CLOBBER, VOIDmode, gen_reg_rtx ( SImode ));
    rtx set_exp = gen_rtx ( SET, VOIDmode, operands[0],
			   gen_rtx ( LE, VOIDmode, cc0_rtx, const0_rtx ));
        
    emit_insn ( gen_rtx ( PARALLEL, VOIDmode,
			 gen_rtvec ( 2, set_exp, clobber_exp )));
    DONE;
}" )
    
( define_insn ""
  [ ( parallel [ ( set ( match_operand:SI 0 "register_operand" "=&D" )
		       ( le ( cc0 ) ( const_int 0 )))
		 ( clobber ( match_operand:SI 1 "register_operand" "=D" )) ] )
  ]
  ""
  "move	#>1,%1\;move	#0,%0\;tle	%1,%0" )

( define_insn "ble"
  [ ( set ( pc )
	  ( if_then_else ( le ( cc0 )
			      ( const_int 0 ))
			 ( label_ref ( match_operand 0 "" "" ))
			 ( pc ))) ]
  ""
  "ble	%l0" )

( define_expand "sleu"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( leu ( cc0 ) ( const_int 0 ))) ]
  ""
  "
{
    rtx clobber_exp = gen_rtx ( CLOBBER, VOIDmode, gen_reg_rtx ( SImode ));
    rtx set_exp = gen_rtx ( SET, VOIDmode, operands[0],
			   gen_rtx ( LEU, VOIDmode, cc0_rtx, const0_rtx ));
        
    emit_insn ( gen_rtx ( PARALLEL, VOIDmode,
			 gen_rtvec ( 2, set_exp, clobber_exp )));
    DONE;
}" )
    
( define_insn ""
  [ ( parallel [ ( set ( match_operand:SI 0 "register_operand" "=&D" )
		       ( leu ( cc0 ) ( const_int 0 )))
		 ( clobber ( match_operand:SI 1 "register_operand" "=D" )) ] )
  ]
  ""
  "move	#>1,%1\;move	#0,%0\;tle	%1,%0" )

( define_insn "bleu"
  [ ( set ( pc )
	  ( if_then_else ( leu ( cc0 )
			       ( const_int 0 ))
			 ( label_ref ( match_operand 0 "" "" ))
			 ( pc ))) ]
  ""
  "ble	%l0" )


;;
;;  ...........................................................................
;;
;;          CONDITIONAL JUMPS WITH INVERTED REGISTER ALLOCATION
;;
;;  ...........................................................................
;;

( define_insn ""
  [ ( set ( pc )
	  ( if_then_else ( eq ( cc0 )
			      ( const_int 0 ))
			 ( pc )
			 ( label_ref ( match_operand 0 "" "" )))) ]
  ""
  "bne	%l0" )

( define_insn ""
  [ ( set ( pc )
	  ( if_then_else ( equ ( cc0 )
 		 	       ( const_int 0 ))
			 ( pc )
			 ( label_ref ( match_operand 0 "" "" )))) ]
  ""
  "bne	%l0" )

( define_insn ""
  [ ( set ( pc )
	  ( if_then_else ( ne ( cc0 )
			      ( const_int 0 ))
			 ( pc )
			 ( label_ref ( match_operand 0 "" "" )))) ]
  ""
  "beq	%l0" )

( define_insn ""
  [ ( set ( pc )
	  ( if_then_else ( neu ( cc0 )
			       ( const_int 0 ))
			 ( pc )
			 ( label_ref ( match_operand 0 "" "" )))) ]
  ""
  "beq	%l0" )

( define_insn ""
  [ ( set ( pc )
	  ( if_then_else ( gt ( cc0 )
			      ( const_int 0 ))
			 ( pc )
			 ( label_ref ( match_operand 0 "" "" )))) ]
  ""
  "ble	%l0" )

( define_insn ""
  [ ( set ( pc )
	  ( if_then_else ( gtu ( cc0 )
			       ( const_int 0 ))
			 ( pc )
			 ( label_ref ( match_operand 0 "" "" )))) ]
  ""
  "ble	%l0" )

( define_insn ""
  [ ( set ( pc )
	  ( if_then_else ( lt ( cc0 )
			      ( const_int 0 ))
			 ( pc )
			 ( label_ref ( match_operand 0 "" "" )))) ]
  ""
  "bge	%l0" )

( define_insn ""
  [ ( set ( pc )
	  ( if_then_else ( ltu ( cc0 )
			       ( const_int 0 ))
			 ( pc )
			 ( label_ref ( match_operand 0 "" "" )))) ]
  ""
  "bge	%l0" )

( define_insn ""
  [ ( set ( pc )
	  ( if_then_else ( ge ( cc0 )
			      ( const_int 0 ))
			 ( pc )
			 ( label_ref ( match_operand 0 "" "" )))) ]
  ""
  "blt	%l0" )

( define_insn ""
  [ ( set ( pc )
	  ( if_then_else ( geu ( cc0 )
			       ( const_int 0 ))
			 ( pc )
			 ( label_ref ( match_operand 0 "" "" )))) ]
  ""
  "blt	%l0" )


( define_insn ""
  [ ( set ( pc )
	  ( if_then_else ( le ( cc0 )
			      ( const_int 0 ))
			 ( pc )
			 ( label_ref ( match_operand 0 "" "" )))) ]
  ""
  "bgt	%l0" )


( define_insn ""
  [ ( set ( pc )
	  ( if_then_else ( leu ( cc0 )
			       ( const_int 0 ))
			 ( pc )
			 ( label_ref ( match_operand 0 "" "" )))) ]
  ""
  "bgt	%l0" )


;;
;;  ...........................................................................
;;
;;          CONDITIONALY STORE ZERO OR NON-ZERO
;;
;;  ...........................................................................
;;

;;
;;  ...........................................................................
;;
;;          UNCONDITIONAL JUMP
;;
;;  ...........................................................................
;;

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

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

( define_expand "tablejump"
  [ ( parallel [ ( set ( pc ) ( match_operand:SI 0 "memory_operand" "m" ))
		 ( clobber ( match_operand:SI 1 "register_operand" "=A" ))
		 ( use ( label_ref ( match_operand 2 "" "" ))) ] ) ]
  ""
  "
{
    rtx addr_reg = force_reg ( Pmode, XEXP ( operands[0], 0 ));
    
    if ( TARGET_P_MEM_SWITCHTABLE )
    {
	emit_insn 
	    ( gen_rtx
	     ( PARALLEL, VOIDmode, 
	      gen_rtvec ( 4, 
			gen_rtx ( SET, VOIDmode, pc_rtx,
				 gen_rtx ( MEM, Pmode, addr_reg )),
			gen_rtx ( CLOBBER, VOIDmode, operands[1] ),
			gen_rtx ( USE, VOIDmode,
				 gen_rtx ( LABEL_REF, VOIDmode, operands[2] )),
			gen_rtx ( CLOBBER, VOIDmode, gen_reg_rtx ( Pmode )))));
	DONE;
    }
}" )

( define_insn ""
   [ ( parallel [ ( set ( pc ) ( mem:SI
				( match_operand:SI 0 "register_operand" "A" )))
		  ( clobber ( match_operand:SI 1 "register_operand" "=A" ))
		  ( use ( label_ref ( match_operand 2 "" "" ))) ] ) ]
  "! TARGET_P_MEM_SWITCHTABLE"
  "*
{ return ( TARGET_PIC ) ?
      \"move	x:(%0),%1\;jmp	%1\" :
      \"move	x:(%0),%1\;jmp	%1\"; }" )

( define_insn ""
   [ ( parallel [ ( set ( pc ) ( mem:SI
				( match_operand:SI 0 "register_operand" "A" )))
		  ( clobber ( match_operand:SI 1 "register_operand" "=A" ))
		  ( use ( label_ref ( match_operand 2 "" "" ))) 
		  ( clobber ( match_operand:SI 3 "register_operand" "=DQ" ))
		  ] ) ]
  "TARGET_P_MEM_SWITCHTABLE"
  "move	p:(%0),%3\;move	%3,%1\;jmp	%1" )

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

( define_insn "call"
  [ ( call ( match_operand:SI 0 "register_or_restricted_memory_operand" "mA" )
	   ( match_operand:SI 1 "immediate_operand" "i" )) ]
  ""
  "*
{
    clear_n_reg_values ( );
    
    if ( REG == GET_CODE ( XEXP ( operands[0], 0 )))
    {
	operands[0] = XEXP ( operands[0], 0 );
    }

    switch ( INTVAL ( operands[1] ))
    {
    case 0:
	return \"jsr	%0\";
	
    case 1:
	return \"jsr	%0\;move	(r2)-\";
	
    case 2:
	return \"jsr	%0\;move	(r2)-\;move	(r2)-\";
	
    default:
	return \"jsr	%0\;move	#-(%q1),n2\;move	(r2)+n2\";
    }
}" )

( define_insn "call_value"
  [ ( set ( match_operand 0 "" "" )
	  ( call
	    ( match_operand:SI 1 "register_or_restricted_memory_operand" "mA" )
	    ( match_operand:SI 2 "immediate_operand" "i" ))) ]
  ""
  "*
{
    clear_n_reg_values ( );
    
    if ( REG == GET_CODE ( XEXP ( operands[1], 0 )))
    {
	operands[1] = XEXP ( operands[1], 0 );
    }
    
    switch ( INTVAL ( operands[2] ))
    {
    case 0:
	return \"jsr	%1\";
	
    case 1:
	return \"jsr	%1\;\"
	       \"move	(r2)-\";
	
    case 2:
	return \"jsr	%1\;\"
	       \"move	(r2)-\;\"
	       \"move	(r2)-\";
	
    default:
	return \"jsr	%1\;\"
	       \"move	#-(%q2),n2\;\"
	       \"move	(r2)+n2\";
    }
}" )

;;
;;  ...........................................................................
;;
;;          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 \"bsr	F__stack_check\";
    }
    else
    {
	return \"\";
    }
}" )

;;
;;  ...........................................................................
;;
;;          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" "D,Q" )))
    ( set ( match_dup 0 )
	  ( plus:SI ( match_dup 1 )
		    ( match_dup 2 )))
  ]
  "( ! rtx_equal_p (operands[0], operands[2] ))" 
  "" )

;;- 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:

