;;- Machine description for the Motorola dsp564XX 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.
;;  %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.
;;  %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 ( MEM == GET_CODE ( operands[0] ) &&
	( MEM == GET_CODE ( operands[1] ) ||
	 CONSTANT_P ( operands[1] ) ||
	 CONST_DOUBLE == GET_CODE ( operands[1] )))
    {
	operands[1] = force_reg ( QImode, operands[1] );
    }
}" )

( define_insn ""
  [ ( set ( match_operand:QI 0 "register_operand" "=r" )
	  ( match_operand:QI 1 "general_operand" "<>mri" )) ]
  ""
  "move	%e1,%0" )

( define_insn ""
  [ ( set ( match_operand:QI 0 "general_operand" "=<>mr" )
	  ( match_operand:QI 1 "register_operand" "r" )) ]
  ""
  "move	%e1,%0" )

( define_expand "movsi"
  [ ( set ( match_operand:SI 0 "general_operand" "" )
	  ( match_operand:SI 1 "general_operand" "" )) ]
  ""
  "
{
    if ( MEM == GET_CODE ( operands[0] ) &&
	( MEM == GET_CODE ( operands[1] ) ||
	 CONSTANT_P ( operands[1] ) ||
	 CONST_DOUBLE == GET_CODE ( operands[1] )))
    {
	operands[1] = force_reg ( SImode, operands[1] );
    }
}" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "register_operand" "=r" )
	  ( match_operand:SI 1 "general_operand" "<>mri" )) ]
  ""
  "move	%e1,%0" )

( define_insn ""
  [ ( set ( match_operand:SI 0 "general_operand" "=<>mr" )
	  ( match_operand:SI 1 "register_operand" "r" )) ]
  ""
  "move	%e1,%0" )

( define_expand "movdi"
  [ ( set ( match_operand:DI 0 "general_operand" "" )
	  ( match_operand:DI 1 "general_operand" "" )) ]
  ""
  "
{
    if ( MEM == GET_CODE ( operands[0] ) &&
	( MEM == GET_CODE ( operands[1] ) ||
	 CONSTANT_P ( operands[1] ) ||
	 CONST_DOUBLE == GET_CODE ( 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 "movdf"
  [ ( set ( match_operand:DF 0 "general_operand" "" )
	  ( match_operand:DF 1 "general_operand" "" )) ]
  ""
  "
{
    if ( MEM == GET_CODE ( operands[0] ) &&
	( MEM == GET_CODE ( operands[1] ) ||
	 CONSTANT_P ( operands[1] ) ||
	 CONST_DOUBLE == GET_CODE ( 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 "" "" ))
		 ( set ( match_operand:SI 3 "" "" )
		       ( plus:SI ( match_dup 3 ) ( match_dup 2 )))
		 ( set ( match_operand:SI 4 "" "" )
		       ( plus:SI ( match_dup 4 ) ( match_dup 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[3] = XEXP ( operands[0], 0 );

    operands[1] = copy_rtx ( operands[1] );
    XEXP ( operands[1], 0 ) = force_reg ( Pmode, XEXP ( operands[1], 0 ));
    operands[4] = 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" ))
	( set ( match_dup 0 ) ( plus:SI ( match_dup 0 ) ( match_dup 2 )))
	( set ( match_dup 1 ) ( plus:SI ( match_dup 1 ) ( match_dup 2 ))) ] ) ]
  ""
  "*
{
    operands[3] = gen_label_rtx ( );
    
    return \"do	%2,%l3\;move	x:(%1)+,%j1\;move	%j1,x:(%0)+\\n%l3\";
}" )

;;
;;  ...........................................................................
;;
;;          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] )"
  "*
{
 abort ( );
/*    clear_n_reg_values ( ); */
    
    return \"move	%2,%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	%5,%j1\;lea	(%1)+%j1,%j1\;\" );
    which_alternative = 1;
    abort();
/*    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 ( DSP564_B_REGNUM < REGNO ( operands[0] )) ?
 \"lea	(%0)+,%0\" : \"incw	%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 ( DSP564_B_REGNUM < REGNO ( operands[0] )) ?
 \"lea	(%0)+,%0\;lea	(%0)+,%0\" : \"incw	%0\;incw	%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 ( DSP564_B_REGNUM < REGNO ( operands[0] )) ?
 \"move	(%0)-\" : \"decw	%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 ( DSP564_B_REGNUM < REGNO ( operands[0] )) ?
 \"move	(%0)-\;move	(%0)-\" : \"decw	%0\;decw	%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	%2,%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\;move	%e0,%0\" : \"add	%2,%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\;move	%e0,%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" ))) ]
  ""
  "jsr	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)-\";
	}
    }
    
    operands[2] = gen_rtx ( CONST_INT, VOIDmode, - INTVAL ( operands[2] ));
    
    return \"move	%2,%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 ( DSP564_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 ( DSP564_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 ( DSP564_B_REGNUM < REGNO ( operands[0] )) ?
 \"lea	(%0)+,%0\" : \"incw	%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 ( DSP564_B_REGNUM < REGNO ( operands[0] )) ?
 \"lea	(%0)+,%0\;lea	(%0)+,%0\" : \"incw	%0\;incw	%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" ))) ]
  ""
  "*
{
    operands[2] = gen_rtx ( CONST_INT, VOIDmode, - INTVAL ( operands[2] ));

    return \"move	%2,%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 "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" ))) ]
  ""
  "jsr	fsub_%i2%0" )

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

( 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" ))) ]
  ""
  "mpy	%2,%1,%0\;asr	%0\;move	%h0,%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" ))) ]
  ""
  "mpy	%2,%1,%0\;asr	%0\;move	%h0,%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"
  "jsr	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\;move	%e0,%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"
  "jsr	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" ))) ]
  ""
  "jsr	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"
  "jsr	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\;\"
            \"jmi	<%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\;\"
            \"jcc	<%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\;\"
            \"jmi	<%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\;\"
            \"jcc	<%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 \"jsr	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"
  "jsr	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\;\"
            \"jmi	<%l3\;\"
            \"ori	#$80,ccr\"
\"\\n%l3\;\"
            \"abs	%0\;\"
            \"asr16	%0\;\"
            \"asl	%0\;\"
            \"rep	#$10\;\"
            \"div	%2,%0\;\"
            \"move	%e0,%0\;\"
	    \"tst	%2\;\"
	    \"jmi	<%l7\;\"
	    \"add	%2,%0\;\"
	    \"jmp	<%l6\"
\"\\n%l7\;\"
	    \"sub	%2,%0\"
\"\\n%l6\;\"
	    \"asr	%0\;\"
            \"bftstl	#$0080,sr\;\"
            \"jcc	<%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\;\"
            \"jmi	<%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\;\"
	    \"jmi	<%l7\;\"
	    \"add	%2,%0\;\"
	    \"jmp	<%l6\"
\"\\n%l7\;\"
	    \"sub	%2,%0\"
\"\\n%l6\;\"
	    \"asr	%0\;\"
            \"bftstl	#$0080,sr\;\"
            \"jcc	<%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 \"jsr	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" ))) ]
  ""
  "jsr	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" ))) ]
  ""
  "jsr	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" ))) ]
  ""
  "jsr	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" ))) ]
  ""
  "jsr	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\;move	%e0,%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\;move	#0,%k0\"; }" )

;;
;;  ...........................................................................
;;
;;          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\;move	%e0,%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\;move	%e0,ssh\;move	%h0,%e0\;move	ssh,%h0\;and	%2,%0\;move	%e0,ssh\;move	%h0,%0\;move	ssh,%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" "Q" ))) ]
  ""
  "or	%2,%0\;move	%e0,%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\;move	%e0,ssh\;move	%h0,%e0\;move	ssh,%h0\;or	%2,%0\;move	%e0,ssh\;move	%h0,%0\;move	ssh,%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" "Q" ))) ]
  ""
  "eor	%2,%0\;move	%e0,%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\;move	%e0,ssh\;move	%h0,%e0\;move	ssh,%h0\;eor	%2,%0\;move	%e0,ssh\;move	%h0,%0\;move	ssh,%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" ))) ]
  ""
  "neg	%0\;decw	%0\;move	%e0,%0" )

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

( define_insn "ashlsi3"
  [ ( 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\;move	%e0,%0\";
    }
    else
    {
	return \"tst	%2\;ble	<%l3\;do	%2,%l3\;asl	%0\\n%l3\;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 "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 "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\;move	%e0,%0\";
    }
    else
    {
	return \"tst	%2\;ble	<%l3\;do	%2,%l3\;asl	%0\\n%l3\;move	%e0,%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\;asl	%0\\n%l3\;move	%e0,%0\";
    }
    else
    {
	return \"tst	%2\;ble	<%l3\;do	%2,%l3\;asl	%0\\n%l3\;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 "register_operand" "DQ" ))) ]
  ""
  "*
{
    operands[3] = gen_label_rtx ( );
    
    if ( TARGET_REP )
    {
	return \"tst	%2\;ble	<%l3\;move	#0,%k0\;rep	%2\;asr	%0\\n%l3\;move	%e0,%0\";
    }
    else
    {
	return \"tst	%2\;ble	<%l3\;move	#0,%k0\;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\;move	%e0,%0\";
    }
    else
    {
	return \"tst	%2\;ble	<%l3\;do	%2,%l3\;asl	%0\\n%l3\;move	%e0,%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\;move	#0,%k0\;rep	%2\;asr	%0\\n%l3\;move	%e0,%0\";
    }
    else
    {
	return \"tst	%2\;ble	<%l3\;move	#0,%k0\;do	%2,%l3\;asr	%0\\n%l3\;move	%e0,%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 )"
  "*
{
    extern enum mdep_cc_info next_cc_use ( );
    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 ))
		    {
			delete_insn ( relevant_insn );
		    }
		    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
		    {
			delete_insn ( relevant_insn );
		    }
		}
	    }
	}
	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_UNSIGNED;

    return \"move	#0,%k0\;move	#0,%k1\;cmp	%1,%0\";
}" )

( define_insn "cmpsi"
  [ ( set ( cc0 )
          ( compare ( match_operand:SI 0 "register_operand" "D" )
                    ( match_operand:SI 1 "register_operand" "DQ" ))) ]
  ""
  "*
{
    extern enum mdep_cc_info next_cc_use ( );
    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 ))
		    {
			delete_insn ( relevant_insn );
		    }
		    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
		    {
			delete_insn ( relevant_insn );
		    }
		}
	    }
	}
	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_SIGNED;

    return \"cmp	%1,%0\";
}" )

( define_insn ""
  [ ( set ( cc0 )
          ( compare ( match_operand:DI 0 "register_operand" "D" )
                    ( match_operand:DI 1 "register_operand" "D" ))) ]
  "UNSIGNED_COMPARE_P( insn )"
  "*
{
    extern enum mdep_cc_info next_cc_use ( );
    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 ))
		    {
			delete_insn ( relevant_insn );
		    }
		    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
		    {
			delete_insn ( relevant_insn );
		    }
		}
	    }
	}
	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_UNSIGNED;

    return \"move	#0,%k0\;move	#0,%k1\;cmp	%1,%0\";
}" )

( define_insn "cmpdi"
  [ ( set ( cc0 )
          ( compare ( match_operand:DI 0 "register_operand" "D" )
                    ( match_operand:DI 1 "register_operand" "D" ))) ]
  ""
  "*
{
    extern enum mdep_cc_info next_cc_use ( );
    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 ))
		    {
			delete_insn ( relevant_insn );
		    }
		    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
		    {
			delete_insn ( relevant_insn );
		    }
		}
	    }
	}
	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_SIGNED;

    return \"cmp	%1,%0\";
}" )

( 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 \"jsr	fcmp_%i1%0\";
    }
}" )

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

( define_insn "tstsi"
  [ ( set ( cc0 ) ( match_operand:SI 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 "tstdi"
  [ ( set ( cc0 ) ( match_operand:DI 0 "general_operand" "D" )) ]
  ""
  "*
{
    if ( CC_UNSIGNED == ( cc_status.mdep = next_cc_use ( insn )))
    {
	return \"move	#0,%k0\;tst	%0\";
    }
    else
    {
	return \"tst	%0\";
    }
}" )

;;
;;  ...........................................................................
;;
;;          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" ))) ]
  ""
  "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 "fixdfsi2"
  [ ( set ( match_operand:SI 0 "register_operand" "=D" )
	  ( fix:SI ( match_operand:DF 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 "floatunsdidf2"
  [ ( set ( match_operand:DF 0 "register_operand" "=D" )
	  ( unsigned_float:DF ( 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 "fixdfdi2"
  [ ( set ( match_operand:DI 0 "register_operand" "=D" )
	  ( fix:DI ( match_operand:DF 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_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 ))) ] ) ]
  ""
  "*
{
    extern void record_address_regs_used ( );
    
    /* we must scan forward and make sure that there is at least one non-do
     * insn between this insn and the target label. If not, 86 the loop. 
     * BTW, a nop instruction doesn't count.
     */
    rtx scan = insn;
    
    while ( scan && ( operands[1] != scan ))
    {
	if (( INSN == GET_CODE ( scan )) && 
	    ( const0_rtx != PATTERN ( scan )))
	{
	    break;
	}
        scan = NEXT_INSN ( scan );
    }
    
    if ( ! scan )
    {
	/* do without corresponding od ! */
	abort ( );
    }
    if (( scan == operands[1] ) ||
	( which_alternative && ( 1 == INTVAL ( operands[0] ))))
    {
	/* we're not really doing a do; record that no conflicts are 
	 * possible.
	 */
	record_address_regs_used ( const0_rtx );

	/* decrement the number of uses at the target label. */

	-- LABEL_NUSES ( operands[1] );

	return \"\";
    }

    /* record potential r/n register conflicts. */
    record_address_regs_used ( PATTERN ( scan ));

    if ( which_alternative )
    {
	return \"do	%0,%l1\";
    }
    else
    {
	if ( IS_SRC_OR_MPY_P ( REGNO ( operands[0] )))
	{
	    return \"do	%0,%l1\";
	}
	else
	{
	    return \"do	%e0,%l1\";
	}
    }
}" )

;; 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 "" "" )) ] ) ]
  ""
  "*
{
    rtx scan = PREV_INSN ( insn );
    
    while ( scan && 
	   (( INSN != GET_CODE ( scan )) || 
	    /* ignore latent nop insns! */
	    ( const0_rtx == PATTERN ( scan ))) &&
	   ( JUMP_INSN != GET_CODE ( scan )))
    {
	scan = PREV_INSN ( scan );
    }
    if ( ! scan )
    {
	/* od without corresponding do ! */
	abort ( );
    }
    if ( JUMP_INSN == GET_CODE ( scan ))
    {
	/* pop the stack - no chance of conflict. */
	(void) conflicting_address_regs_set_p ( const0_rtx );
	
	/* but hey- auto bonejob! we can't have a jmp as the last insn
	   within the DO! */

	return \"nop\";
    }
    if ( INSN == GET_CODE ( scan ))
    {
	/* if we have a conflict, emit a noop to sw interlock. */
	if ( conflicting_address_regs_set_p ( PATTERN ( scan )))
	{
	    return \"nop\";
	}
    }
    return \"\";
}" )

( 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_insn "beq"
  [ ( set ( pc )
	  ( if_then_else ( eq ( cc0 )
			      ( const_int 0 ))
			 ( label_ref ( match_operand 0 "" "" ))
			 ( pc ))) ]
  ""
  "jeq	%l0" )

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

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

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

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

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

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

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

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

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

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

( define_insn "bleu"
  [ ( set ( pc )
	  ( if_then_else ( leu ( cc0 )
			       ( const_int 0 ))
			 ( label_ref ( match_operand 0 "" "" ))
			 ( pc ))) ]
  ""
  "jle	%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 "" "" )))) ]
  ""
  "jne	%l0" )

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

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

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

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

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

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

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

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

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


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


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


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

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

( define_insn "jump"
  [ ( set ( pc )
	  ( label_ref ( match_operand 0 "" "" ))) ]
  ""
  "jmp	%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 "" "" ))) 
		  ( clobber ( match_operand:SI 3 "register_operand" "=DQ" ))
		  ] ) ]
  "TARGET_P_MEM_SWITCHTABLE"
  "move	p:(%0),%3\;move	%3,%1\;jmp	%1" )

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

( define_expand "call"
  [ ( call ( match_operand:SI 0 "general_operand" "mA" )
	   ( match_operand:SI 1 "immediate_operand" "i" ))
  ]
  ""
  "
{
    emit_insn ( 
	       gen_rtx ( PARALLEL,
			VOIDmode,
			gen_rtvec ( 1,
				   gen_rtx ( CALL, 
					    VOIDmode,
					    operands[0], operands[1] ))));
    DONE;
}" )

( define_insn ""
  [ ( parallel [ ( call ( match_operand:SI 0 "general_operand" "mA" )
			( match_operand:SI 1 "immediate_operand" "i" )) ] )
  ]
  ""
  "*
{
 abort();
/*    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:
	operands[1] = gen_rtx ( CONST_INT, VOIDmode, - INTVAL ( operands[1] ));
	
	return \"jsr	%0\;move	%1,n2\;move	(r2)+n2\";
    }
}" )

( define_expand "call_value"
  [ ( set ( match_operand 0 "" "" )
	  ( call ( match_operand:SI 1 "general_operand" "mA" )
		 ( match_operand:SI 2 "immediate_operand" "i" )))
  ]
  ""
  "
{
    emit_insn ( 
	       gen_rtx ( PARALLEL, VOIDmode,
			gen_rtvec ( 1,
				   gen_rtx ( SET, VOIDmode,
					    operands[0],
					    gen_rtx ( CALL, VOIDmode,
						     operands[1],
						     operands[2] )))));
    DONE;
}" )

( define_insn ""
  [ ( parallel [ ( set ( match_operand 0 "" "" )
		       ( call ( match_operand:SI 1 "general_operand" "mA" )
			      ( match_operand:SI 2 "immediate_operand" "i" )))
	       ] )
  ]
  ""
  "*
{
abort();
/*    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:
	operands[2] = gen_rtx ( CONST_INT, VOIDmode, - INTVAL ( operands[2] ));
	
	return \"jsr	%1\;move	%2,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 \"jsr	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:

