/* lfr ret should little endian */

#define const13(x) ((x) > -4096 && (x) < 4096)
#define NULL 0
#include "mach_em.h"

define(`RETH_LD',`reg_o1')
define(`RETL_LD',`reg_o0')
define(`RETH_ST',`reg_i1')
define(`RETL_ST',`reg_i0')
define(`LIN_NO',`%g6')
define(`FIL_NAM',`%g7')

define(`BP_OFFSET',`'WINDOWSIZE)
define(`'`EM_BSIZE',EM_BSIZE)
define(STACK_CLICK,4)

#if RESOLV_debug
define(Comment0)
define(Comment)
define(Comment2)
#else
define(Comment0,; `'`)' ; `'`/* */'"	! $1"		; code_combiner`'`(' )
define(Comment, ; `'`)' ; `'`/* */'"	! $1 $2"	; code_combiner`'`(' )
define(Comment2,; `'`)' ; `'`/* */'"	! $1 $2 $3"	; code_combiner`'`(' )
#endif

define(MAX_INT, 0x7fffffff)
define(E_EM_CUF, 100)
define(E_EM_CFF, 101)
define(E_EM_CFI, 102)
define(E_EM_CFU, 103)
#define MAX_UNROLL	16
#undef FAST_LIN_LNI_FIL


define( narg4,
C_$1_narg	==>
`	{
		reg_t a;
		int n;
		
		Comment0( $1_narg );
		if (type_of_tos() == T_cst)
		{
			n= pop_const(NULL);
			C_$1 (n);
		}
		else
		{
			a= pop_reg();
			force_alloc_output();
			"cmp	$a, 4";
			"be	1f";
			"set	EILLINS, $reg_o0";
			"call	trp";
			"nop";
		"1:";
			free_reg(a);
			free_output();
		C_$1 (4);
		}
	}.
'
)


/******************************************************************************/
/*                                                                            */
/*			Group 1 : Load instructions			      */
/*							 		      */
/******************************************************************************/

/*	%fp : frame pointer
 *	%sp : stack pointer
 *	RETH_XX: High part of return value
 *	RETL_XX: Low part of return value
 *	LIN_NO : lin_no
 *	FIL_NAM: Fil_nam
 */

C_loc		==>
			Comment( loc , $1 );
			push_const($1).


C_lol		==>
		Comment( lol , $1 );
		{
			reg_t S1;

			if (S1 = find_local($1, NULL)) {
				soft_alloc_reg(S1);
				push_reg(S1);
			} else {
				soft_alloc_reg(reg_lb);
				push_reg(reg_lb);
				inc_tos($1);
				push_const(4);
				C_los(EM_WSIZE);
			}
		}.


C_loe..		==>
		Comment2( loe.. , $1, $2 );
		{
#ifdef FAST_LIN_LNI_FIL
			if ((int*)($1) == (int*)"hol0")
				if ($2 == 0)
					push_reg(reg_lin);
				else if ($2 == 4)
					push_reg(reg_fil);
				else
					arg_error("loe.. hol0+", $2);
			else {
#endif
				push_ext($1);
				inc_tos($2);
				push_const(4);
				C_los(EM_WSIZE);
#ifdef FAST_LIN_LNI_FIL
			}
#endif
		}
		.

C_lil		==>
		Comment( lil , $1 );
		{
			reg_t S1;
			reg_t S2;

			if (S1 = find_local($1, NULL)) {
				S2 = alloc_reg();
				"ld	[$S1], $S2";
				push_reg(S2);
			} else {
				soft_alloc_reg(reg_lb);
				push_reg(reg_lb);
				inc_tos($1);
				push_const(4);
				C_los(EM_WSIZE);
				push_const(4);
				C_los(EM_WSIZE);
			}
		}.

C_lof		==>
			Comment( lof , $1 );
			inc_tos($1);
			push_const(4);
			C_los(EM_WSIZE).

C_lal		==>
			Comment( lal , $1 );
			soft_alloc_reg(reg_lb);
			push_reg(reg_lb);
			inc_tos($1).

C_lae..		==>
			Comment2( lae.. , $1, $2 );
			push_ext($1);
			inc_tos($2).

C_lxl
	$1 == 0	==>
			Comment( lxl , $1 );
			soft_alloc_reg(reg_lb);
			push_reg(reg_lb).
	$1 == 1	==>
			Comment( lxl , $1 );
			soft_alloc_reg(reg_lb);
			push_reg(reg_lb);
			inc_tos(EM_BSIZE);
			push_const(4);
			C_los(EM_WSIZE).
	default ==>
			Comment( lxl , $1 );
			{
				reg_t a;
				reg_t b;
				reg_t c;
				const_str_t n_str;

				a = alloc_reg();
				b = alloc_reg();
				c = alloc_reg();
				sprint(n_str, "%d", $1);
				"set	$n_str, $a";
				"mov 	$reg_lb, $b";
			"1:	ld	[$b + EM_BSIZE], $c";
				"deccc	$a";
				"bnz	1b";
				"mov	$c, $b";
				push_reg(b);
				free_reg(a);
				free_reg(c);
			}.

C_lxa	==>
	C_lxl($1);
	inc_tos(EM_BSIZE).

C_loi
	( $1 == 1 ) ||
	( $1 == 2 ) ||
	( $1 % 4 == 0 )	==>
			Comment( loi , $1 );
			push_const($1);
			C_los(EM_WSIZE).

	default		==>
				arg_error( "loi", $1).

C_los
	$1 == 4  ==>
	{
		reg_t a;
		reg_t b;
		reg_t c;
		int i;
		char *LD;
		arith size;
		const_str_t n;
		const_str_t size_str;

		Comment( los, $1);
		if (type_of_tos() == T_cst && top_const() <= MAX_UNROLL) {
			size = pop_const(size_str);
			if (size <= 4) {
				switch (size) {
				case 1: LD = "ldub"; break;
				case 2: LD = "lduh"; break;
				case 4: LD = "ld"; break;
				default: arg_error("C_los", size);
				}
				b = alloc_reg();
				if (type_of_tos() & T_reg2)
				{
					a= pop_reg_reg(&c);
					"$LD	[$a+$c], $b";
					free_reg(a);
					free_reg(c);
				}
				else
				{
					a = pop_reg_c13(n);
					"$LD	[$a+$n], $b";
					free_reg(a);
				}
				push_reg(b);
			} else if (size <= MAX_UNROLL) {    /* SUB-OPTIMAL */
				inc_tos(size-4);
				for (i = 0; i < size; i += 4) {
					b = alloc_reg();
					if (type_of_tos() & T_reg2)
					{
						a= pop_reg_reg(&c);
						"ld	[$a+$c], $b";
						push_reg(b);
						push_reg(a);
						inc_tos_reg(c);
					}
					else
					{
						a = pop_reg_c13(n);
						"ld	[$a+$n], $b";
						push_reg(b);
						if (n[0] == '-' || isdigit(n[0]))
						{
							push_reg(a);
							inc_tos(atoi(n));
						}
						else
						{
							b= alloc_reg();
							"add	$a, $n, $b";
							push_reg(b);
							free_reg(a);
						}
					}
					inc_tos(-4);
				}
				pop_nop(1);
			} else
				arg_error ("loi",  size);
		}
		else {
			a = pop_reg();	/* count */
			b = pop_reg();	/* addr */
			c = alloc_reg();
			flush_cache();
			"sub	$reg_sp, $a, $reg_sp"	/* HACK */
		"1:	 deccc	4, $a"
			"ld	[$b+$a], $c"
			"bnz	1b"
			"st	$c, [$reg_sp+$a]"	/* delay */
			free_reg(a);
			free_reg(b);
			free_reg(c);
		}
	}.
	default ==>
		arg_error("C_los", $1).


narg4(los)

C_ldl		==>
		Comment( ldl , $1 );
		{
			reg_t S1;
			reg_t S2;

			if (S1 = find_local($1, &S2)) {
				soft_alloc_reg(S1);
				soft_alloc_reg(S2);
				push_double_reg(S1);
			} else {
				soft_alloc_reg(reg_lb);
				push_reg(reg_lb);
				inc_tos($1);
				push_const(8);
				C_los(EM_WSIZE);
			}
		}.


C_lde..		==>
			Comment2( lde.. , $1, $2 );
			push_ext($1);
			inc_tos($2);
			push_const(8);
			C_los(EM_WSIZE).

C_ldf		==>
			Comment( ldf , $1 );
			inc_tos($1);
			push_const(8);
			C_los(EM_WSIZE).

C_lpi		==>
			Comment( lpi , $1 );
			push_ext($1).


/******************************************************************************/
/*                                                                            */
/*			Group 2 : Store instructions			      */
/*							 		      */
/******************************************************************************/

C_stl		==>
		Comment( stl , $1 );
		{
			reg_t S1;

			if ((S1 = find_local($1, NULL))) {
				pop_reg_as(S1);
			} else {
				soft_alloc_reg(reg_lb);
				push_reg(reg_lb);
				inc_tos($1);
				push_const(4);
				C_sts(EM_WSIZE);
			}
		}.

C_ste..		==>
			Comment2( ste.. , $1, $2 );
			push_ext($1);
			inc_tos($2);
			push_const(4);
			C_sts(EM_WSIZE).


C_sil		==>
		Comment( sil , $1 );
		{
			reg_t S1;
			reg_t S2;

			if (S1 = find_local($1, NULL)) {
				S2 = pop_reg();
				"st	$S2, [$S1]";
				free_reg(S2);
			} else {
				soft_alloc_reg(reg_lb);
				push_reg(reg_lb);
				inc_tos($1);
				push_const(4);
				C_los(EM_WSIZE);
				push_const(4);
				C_sts(EM_WSIZE);
			}
		}.

C_stf		==>
			Comment( stf , $1 );
			inc_tos($1);
			push_const(4);
			C_sts(EM_WSIZE).

C_sti
	( $1 == 1) ||
	( $1 == 2) ||
	( $1 % 4 == 0 )	==>
			Comment( sti, $1 );
			push_const($1);
			C_sts(EM_WSIZE).

	default		==>
				arg_error( "sti", $1).


C_sts
	$1 == 4  ==>
	{
		reg_t a;
		reg_t b;
		reg_t c;
		reg_t d;

		arith size;
		const_str_t n;
		const_str_t size_str;
		int i;
		char *ST;

		Comment( sts, $1);
		if (type_of_tos() == T_cst && top_const() <= MAX_UNROLL) {

			size = pop_const(size_str);
			if (size <= 4) {

				switch (size) {
				case 1: ST = "stb"; break;
				case 2: ST = "sth"; break;
				case 4: ST = "st"; break;
				default: arg_error("C_sti", size);
				}
				c= NULL;
				if (type_of_tos() & T_reg2)
					a= pop_reg_reg(&c);
				else
					a = pop_reg_c13(n);
				if (type_of_tos() == T_float) {
					b= pop_float();
					if (size < 4) {
						"st	$b,[%fp+64]";
						free_reg(b);
						b= alloc_reg();
						"ld	[%fp+64],$b";
					}
				}
				else
					b = pop_reg();
				if (c)
				{
					"$ST	$b, [$a+$c]";
					free_reg(c);
				}
				else
					"$ST	$b, [$a+$n]";
				free_reg(a);
				free_reg(b);
			} else if (size <= MAX_UNROLL) {
				for (i = 0; i < size; i+=4) {
					c= NULL;
					if (type_of_tos() & T_reg2)
						a= pop_reg_reg(&c);
					else
						a = pop_reg_c13(n);
					if (type_of_tos() == T_float)
						b= pop_float();
					else
						b = pop_reg();
					if (c)
						"st	$b, [$a+$c]";
					else
						"st	$b, [$a+$n]";
					free_reg(b);
					if (c)
					{
						push_reg(a);
						inc_tos_reg(c);
					}
					else if (n[0] == '-' || isdigit(n[0]))
					{
						push_reg(a);
						inc_tos(atoi(n));
					}
					else
					{
						b= alloc_reg();
						"add	$a, $n, $b";
						push_reg(b);
						free_reg(a);
					}
					inc_tos(4);
				}
				pop_nop(1);
			} else
				arg_error ("sti", size);
		}
		else {
			force_alloc_output();
			d = pop_reg();		/* size */
			a = pop_reg();		/* address */
			flush_cache();
			b = alloc_reg();
			c = alloc_reg();
			"cmp	$d, 4";
			"bg,a	8f";
			"andcc	$d, 3, %g0";	/* delay slot */
			"be,a	4f";
			"ld	[$reg_sp], $b";	/* delay slot */
			"cmp	$d, 1";
			"be,a	1f";
			"ld	[$reg_sp], $b";	/* delay slot */
			"bl	0f";
			"cmp	$d, 2";
			"be	2f";
			"ld	[$reg_sp], $b";	/* delay slot */
		"3:	 set	EILLINS, %o0";
			"call	trp";
			"nop";
			"b	0f";
			"nop";
		"1:";
			"inc	STACK_CLICK, $reg_sp";
			"b	0f";
			"stb	$b, [$a]";	/* delay slot */
		"2:";
			"inc	STACK_CLICK, $reg_sp";
			"b	0f";
			"sth	$b, [$a]";	/* delay slot */
		"4:";
			"inc	STACK_CLICK, $reg_sp";
			"b	0f";
			"st	$b, [$a]";	/* delay slot */
		"8:";
			"bne	3b";
			"nop";
			"mov	$d, $b";
		"9:	 deccc	4, $b";
			"ld	[$reg_sp+$b], $c";
			"bnz	9b";
			"st	$c, [$a+$b]";	/* delay slot */
			"add	$reg_sp, $d, $reg_sp"	/* HACK */
		"0:"
			free_reg(a);
			free_reg(b);
			free_reg(c);
			free_reg(d);
			free_output();
		}
	}.
	default		==>
				arg_error( "sts", $1).

narg4(sts)

C_sdl		==>
		Comment( sdl , $1 );
		{
			reg_t S1;
			reg_t S2;

			S1 = find_local($1, NULL);
			if (S1) 
				pop_double_reg_as(S1);
			else {
				soft_alloc_reg(reg_lb);
				push_reg(reg_lb);
				inc_tos($1);
				push_const(8);
				C_sts(EM_WSIZE);
			}
		}.

C_sde..		==>
			Comment2( sde.. , $1, $2 );
			push_ext($1);
			inc_tos($2);
			push_const(8);
			C_sts(EM_WSIZE).

C_sdf		==>
			Comment( sdf , $1 );
			inc_tos($1);
			push_const(8);
			C_sts(EM_WSIZE).


/******************************************************************************/
/*									      */
/*		Group 3 : Integer arithmetic				      */
/*									      */
/******************************************************************************/


C_adi
	$1 == 4	==>
			Comment( adi , $1 );
			if ((type_of_tos()) == T_cst) {
				arith n;

				n = pop_const(NULL);
				inc_tos(n);
			} else {
				reg_t a;
				reg_t b;
				reg_t c;

				a = pop_reg();
				inc_tos_reg(a);
			}.
	default	==>
				arg_error( "adi", $1).

narg4(adi)

C_sbi
	$1 == 4	==>
			Comment( sbi , $1 );
			if ((type_of_tos()) == T_cst) {
				arith n;

				n = pop_const(NULL);
				inc_tos(-n);
			} else {
				reg_t a;
				reg_t b;
				reg_t c;

				a = pop_reg();
				b = pop_reg();
				c = alloc_reg();
				"sub	$b, $a, $c";
				free_reg(a);
				free_reg(b);
				push_reg(c);
			}.
	default	==>
				arg_error( "sbi", $1).

narg4(sbi)

C_mli
	$1 == 4	==>
	{
		unsigned int n0;
		unsigned int n1;
		reg_t orig;
		reg_t a;
		reg_t b;
		reg_t c;
		unsigned int n;
		const_str_t n_str;

		Comment( mli , $1 );

		if (type_of_tos() == T_cst) {
			n = pop_const(NULL);
			orig = pop_reg();
			c = reg_g0;
			while (n) {
				for (n0 = 0; !(n & 1); n>>=1)
					++n0;
				for (n1 = 0; n & 1; n>>=1)
					++n1;

				if (n0) {
					a = alloc_reg();
					sprint(n_str, "%d", n0);
					"sll	$orig, $n_str, $a";
					free_reg(orig);
					orig = a;
				}
				if (n1 == 1) {
					if (c == reg_g0) {
						soft_alloc_reg(orig);
						c = orig;
					} else {
						a = alloc_reg();
						"add	$c, $orig, $a";
						free_reg(c);
						c = a;
					}
					n <<= n1;
				} else {
					a = alloc_reg();
					sprint(n_str, "%d", n1);
					"sll	$orig, $n_str, $a";
					b = alloc_reg();
					"sub	$a, $orig, $b";
					free_reg(orig);
					orig = a;
					if (c == reg_g0)
						c = b;
					else {
						a = alloc_reg();
						"add	$c, $b, $a";
						free_reg(b);
						free_reg(c);
						c = a;
					}
				}
			}
			push_reg(c);
			free_reg(orig);
		} else {
			force_alloc_output();
			pop_reg_as(reg_o0);
			pop_reg_as(reg_o1);
			"call	mli4";
			"nop"			/* delay */
			free_output();
			forced_alloc_reg(reg_o0);
			push_reg(reg_o0);
		}
	}.
	default	==>
			arg_error( "mli", $1).

narg4(mli)

C_dvi
	$1 == 4	==>
	{
		reg_t a;
		reg_t b;
		int n;
		int n_exp;
		const_str_t n_exp_str;

		Comment( dvi , $1 );
#if MATH_DIVIDE
		if (type_of_tos() == T_cst &&
			power_of_2(top_const(), &n_exp))
		{
			sprint (n_exp_str, "%d", n_exp);
			n= pop_const(NULL);
			a= pop_reg();
			b= alloc_reg();
			"sra	$a, $n_exp_str, $b";
			free_reg(a);
			push_reg(b);
		}
		else
#endif
		{
			force_alloc_output();
			pop_reg_as(reg_o1);	/* denominator */
			pop_reg_as(reg_o0);	/* numerator */
#if MATH_DIVIDE
			"call	mathdvi4";
#else
			"call	dvi4";
#endif
			"nop"
			free_output();
			forced_alloc_reg(reg_o0);
			push_reg(reg_o0);
		}
	}.
	default	==>
			arg_error( "dvi", $1).

narg4(dvi)

C_rmi
	$1 == 4	==>
			Comment( rmi , $1 );
			{
				force_alloc_output();
				pop_reg_as(reg_o1);	/* denominator */
				pop_reg_as(reg_o0);	/* numerator */
#if MATH_DIVIDE
				"call	mathdvi4";
#else
				"call	dvi4";
#endif
				"nop"
				free_output();
				forced_alloc_reg(reg_o1);
				push_reg(reg_o1);
			}.
	default	==>
			arg_error( "rmi", $1).

narg4(rmi)

C_ngi
	$1 == 4	==>
			Comment( ngi , $1 );
			{
				reg_t a;
				reg_t b;

				a = pop_reg();
				b = alloc_reg();
				"sub	%g0, $a, $b";
				push_reg(b);
				free_reg(a);
			}.
	default	==>
			arg_error( "ngi", $1).

narg4(ngi)

C_sli
	$1 == 4	==>
			Comment( sli , $1 );
			{
				reg_t a;
				reg_t b;
				reg_t c;

				b = alloc_reg();
				if ((type_of_tos() == T_cst) &&
					(const13(top_const()))) {
					const_str_t n;

					pop_const(n);
					a = pop_reg();
					"sll	$a, $n, $b";
				} else {
					c = pop_reg();
					a = pop_reg();
					"sll	$a, $c, $b";
					free_reg(c);
				}
				free_reg(a);
				push_reg(b);
			}.
	default	==>
			arg_error( "sli", $1).

narg4(sli)

C_sri
	$1 == 4		==>
			Comment( sri , $1 );
			{
				reg_t a;
				reg_t b;
				reg_t c;

				b = alloc_reg();
				if ((type_of_tos() == T_cst) &&
					(const13(top_const()))) {
					const_str_t n;

					pop_const(n);
					a = pop_reg();
					"sra	$a, $n, $b";
				} else {
					c = pop_reg();
					a = pop_reg();
					"sra	$a, $c, $b";
					free_reg(c);
				}
				free_reg(a);
				push_reg(b);
			}.
	default	==>
			arg_error( "sri", $1).

narg4(sri)

/******************************************************************************/
/*									      */
/*		Group 4 : Unsigned arithmetic 				      */
/*									      */
/******************************************************************************/

C_adu		==>
			Comment( adu , $1 );
		 	C_adi( w).

narg4(adu)

C_sbu		==>
			Comment( sbu , $1 );
		 	C_sbi( w).

narg4(sbu)

C_mlu
	$1 == 4	==>
		Comment( mlu , $1 );
		C_mli($1).
/*
		{
			force_alloc_output();
			pop_reg_as(reg_o0);
			pop_reg_as(reg_o1);
			"call	mlu4";
			"nop"
			free_output();
			forced_alloc_reg(reg_o0);
			push_reg(reg_o0);
		}.
*/
	default	==>
			arg_error( "mlu", $1).

narg4(mlu)

C_dvu
	$1 == 4	==>
	{
		reg_t a;
		reg_t b;
		unsigned n;
		int n_exp;
		const_str_t n_exp_str;

		Comment( dvu , $1 );
		if (type_of_tos() == T_cst &&
			uns_power_of_2(top_const(), &n_exp))
		{
			sprint (n_exp_str, "%d", n_exp);
			n= pop_const(NULL);
			a= pop_reg();
			b= alloc_reg();
			"srl	$a, $n_exp_str, $b";
			free_reg(a);
			push_reg(b);
		}
		else
		{
			force_alloc_output();
			pop_reg_as(reg_o1);	/* denominator */
			pop_reg_as(reg_o0);	/* numerator */
			"call	dvu4";
			"nop"
			free_output();
			forced_alloc_reg(reg_o0);
			push_reg(reg_o0);
		}
	}.
	default	==>
			arg_error( "dvu", $1).

narg4(dvu)

C_rmu
	$1 == 4	==>
		Comment( rmu , $1 );
		{
			force_alloc_output();
			pop_reg_as(reg_o1);
			pop_reg_as(reg_o0);
			"call	dvu4";
			"nop"
			free_output();
			forced_alloc_reg(reg_o1);
			push_reg(reg_o1);
		}.
	default	==>
			arg_error( "rmu", $1).

narg4(rmu)

C_slu		==>
			Comment( slu , $1 );
			C_sli($1).

narg4(slu)

C_sru
	$1 == 4	==>
			{
				reg_t a;
				reg_t b;
				reg_t c;

				Comment( sru , $1 );
				b = alloc_reg();
				if ((type_of_tos() == T_cst) &&
					(const13(top_const()))) {
					const_str_t n;

					pop_const(n);
					a = pop_reg();
					"srl	$a, $n, $b";
				} else {
					c = pop_reg();
					a = pop_reg();
					"srl	$a, $c, $b";
					free_reg(c);
				}
				free_reg(a);
				push_reg(b);
			}.
	default	==>
			arg_error( "sru", $1).

narg4(sru)

/******************************************************************************/
/*									      */
/*		Group 5 : Floating point arithmetic 			      */
/*									      */
/******************************************************************************/

C_adf		==>
	{
		Comment( adf, $1);
		push_const($1);
		C_adf_narg();
	}.

C_adf_narg	==>
	{	
		reg_t f1;
		reg_t f2;
		reg_t f3;
		int n;

		Comment0( adf_narg);
		if (type_of_tos() == T_cst)
		{
			n= pop_const(NULL);
			if (n == EM_WSIZE)
			{
				f1= pop_float();
				f2= pop_float();
				f3= alloc_float();
				"fadds	$f2, $f1, $f3";
				free_reg(f1);
				free_reg(f2);
				push_reg(f3);
			}
			else if (n == EM_DSIZE)
			{
				f1= pop_double(NULL);
				f2= pop_double(NULL);
				f3= alloc_double(NULL);
				"faddd	$f1, $f2, $f3";
				free_double_reg(f1);
				free_double_reg(f2);
				push_double_reg(f3);
			}
			else
				arg_error ("unimp adf", n);
		}
		else
			not_implemented ("adf_narg");
	}.

C_sbf		==>
	{
		Comment( sbf, $1);
		push_const($1);
		C_sbf_narg();
	}.

C_sbf_narg	==>
	{	
		reg_t f1;
		reg_t f2;
		reg_t f3;
		int n;

		Comment0( sbf_narg);
		if (type_of_tos() == T_cst)
		{
			n= pop_const(NULL);
			if (n == EM_WSIZE)
			{
				f1= pop_float();
				f2= pop_float();
				f3= alloc_float();
				"fsubs	$f2, $f1, $f3";
				free_reg(f1);
				free_reg(f2);
				push_reg(f3);
			}
			else if (n == EM_DSIZE)
			{
				f1= pop_double(NULL);
				f2= pop_double(NULL);
				f3= alloc_double(NULL);
				"fsubd	$f2, $f1, $f3";
				free_double_reg(f1);
				free_double_reg(f2);
				push_double_reg(f3);
			}
			else
				arg_error ("unimp sbf", n);
		}
		else
			not_implemented ("sbf_narg");
	}.

C_mlf		==>
	{
		Comment( mlf, $1);
		push_const($1);
		C_mlf_narg();
	}.

C_mlf_narg	==>
	{	
		reg_t f1;
		reg_t f2;
		reg_t f3;
		int n;

		Comment0( mlf_narg);
		if (type_of_tos() == T_cst)
		{
			n= pop_const(NULL);
			if (n == EM_WSIZE)
			{
				f1= pop_float();
				f2= pop_float();
				f3= alloc_float();
				"fmuls	$f2, $f1, $f3";
				free_reg(f1);
				free_reg(f2);
				push_reg(f3);
			}
			else if (n == EM_DSIZE)
			{
				f1= pop_double(NULL);
				f2= pop_double(NULL);
				f3= alloc_double(NULL);
				"fmuld	$f2, $f1, $f3";
				free_double_reg(f1);
				free_double_reg(f2);
				push_double_reg(f3);
			}
			else
				arg_error ("unimp mlf", n);
		}
		else
			not_implemented ("mlf_narg");
	}.

C_dvf		==>
	{
		Comment( dvf, $1);
		push_const($1);
		C_dvf_narg();
	}.

C_dvf_narg	==>
	{	
		reg_t f1;
		reg_t f2;
		reg_t f3;
		int n;

		Comment0( dvf_narg);
		if (type_of_tos() == T_cst)
		{
			n= pop_const(NULL);
			if (n == EM_WSIZE)
			{
				f1= pop_float();
				f2= pop_float();
				f3= alloc_float();
				"fdivs	$f2, $f1, $f3";
				free_reg(f1);
				free_reg(f2);
				push_reg(f3);
			}
			else if (n == EM_DSIZE)
			{
				f1= pop_double(NULL);
				f2= pop_double(NULL);
				f3= alloc_double(NULL);
				"fdivd	$f2, $f1, $f3";
				free_double_reg(f1);
				free_double_reg(f2);
				push_double_reg(f3);
			}
			else
				arg_error ("unimp dvf", n);
		}
		else
			not_implemented ("dvf_narg");
	}.

C_ngf		==>
	{
		Comment( ngf, $1);
		push_const($1);
		C_ngf_narg();
	}.

C_ngf_narg	==>
	{	
		reg_t f1;
		reg_t f2;
		int n;

		Comment0( ngf_narg);
		if (type_of_tos() == T_cst)
		{
			n= pop_const(NULL);
			if (n == EM_WSIZE || n == EM_DSIZE)
			{
				f1= pop_float();
				f2= alloc_float();
				"fnegs	$f1, $f2";
				free_reg(f1);
				push_reg(f2);
			}
			else
				arg_error ("unimp ngf", n);
		}
		else
			not_implemented ("ngf_narg");
	}.

C_fif		==>
	Comment( fif, $1);
	push_const($1);
	C_fif_narg().

C_fif_narg	==>
	{
		int n;
		reg_t a;
		reg_t b;
		reg_t c;
		reg_t d;

		Comment0( fif_narg );
		if (type_of_tos() == T_cst)
		{
			n= pop_const(NULL);

			if (n==4)
			{
				"! unimplemented fif 4";
				"st	%g0, [%g0]"; /* unimp */
			}
			else if (n==8)
			{
				flush_cache();
				"call	fif8";
				"nop";
			}
			else
				arg_error ("fif", n);
		}
		else
		{
			a= alloc_reg();
			flush_cache();
			force_alloc_output();
			b= alloc_reg();
			c= alloc_reg();
			d= pop_reg();
			"cmp	8, $d";
			"be	8f";
			"nop";
			"cmp	4, $d";
			"bne	0f";
			"nop";
		"4:";
			"! unimplemented fif 4";
			"st	%g0, [%g0]";
			"b	1f";
		"0:";
			"set	EILLINS, $reg_o0";
			"call	trp";
			"nop";
			"b	1f";
		"8:";
			"call	fif8";
			"nop";
		"1:";
			free_reg(a);
			free_reg(b);
			free_reg(c);
			free_reg(d);
			free_output();
		}
	}.


C_fef		==>
	Comment( fef, $1);
	push_const($1);
	C_fef_narg().

C_fef_narg	==>
	{
		int n;
		reg_t a;
		reg_t b;
		reg_t c;
		reg_t d;
		reg_t e;

		Comment0( fef_narg );
		if (type_of_tos() == T_cst)
		{
			n= pop_const(NULL);

			if (n==4)
			{
				"! unimplemented fef 4";
				"st	%g0, [%g0]"; /* unimp */
			}
			else if (n==8)
			{
				flush_cache();
				"call	fef8";
				"nop";
			}
			else
				arg_error ("fef", n);
		}
		else
		{
			a= alloc_reg();
			flush_cache();
			force_alloc_output();
			b= alloc_reg();
			c= alloc_reg();
			d= pop_reg();
			"cmp	8, $d";
			"be	8f";
			"nop";
			"cmp	4, $d";
			"bne	0f";
			"nop";
		"4:";
			"! unimplemented fef 4";
			"st	%g0, [%g0]";
			"b	1f";
		"0:";
			"set	EILLINS, $reg_o0";
			"call	trp";
			"nop";
			"b	1f";
		"8:";
			"call	fef8";
			"nop";
		"1:";
			free_reg(a);
			free_reg(b);
			free_reg(c);
			free_reg(d);
			free_output();
		}
	}.

/******************************************************************************/
/*									      */
/*		Group 6 : Pointer arithmetic 				      */
/*									      */
/******************************************************************************/

C_adp		==>
			Comment( adp , $1 );
			inc_tos($1).

C_ads
	$1 == 4	==>
			Comment( ads , $1 );
			if ((type_of_tos()) == T_cst) {
				arith n;

				n = pop_const(NULL);
				inc_tos(n);
			} else {
				reg_t a;
				reg_t b;
				reg_t c;

				a = pop_reg();
				inc_tos_reg(a);
			}.
	default		==>
				arg_error( "ads", $1).

narg4(ads)

C_sbs
	$1 == 4	==>
			Comment( sbs , $1 );

			if ((type_of_tos()) == T_cst) {
				arith n;

				n = pop_const(NULL);
				inc_tos(-n);
			} else {
				reg_t a;
				reg_t b;
				reg_t c;

				a = pop_reg();
				b = pop_reg();
				c = alloc_reg();
				"sub	$b, $a, $c";
				free_reg(a);
				free_reg(b);
				push_reg(c);
			}.
	default	==>
			arg_error( "sbs", $1).

narg4(sbs)

/******************************************************************************/
/*									      */
/*		Group 7 : Increment/decrement/zero			      */
/*									      */
/******************************************************************************/

C_inc		==>
			Comment0( inc  );
			inc_tos(1).

C_inl		==>
		Comment( inl , $1 );
		{
			reg_t S1;

			if (S1 = find_local($1, NULL)) {
				change_reg(S1);
				"inc	1, $S1";
			} else {
				soft_alloc_reg(reg_lb);
				push_reg(reg_lb);
				inc_tos($1);
				C_loi(4);
				C_inc();
				soft_alloc_reg(reg_lb);
				push_reg(reg_lb);
				inc_tos($1);
				C_sti(4);
			}
		}.

C_ine..		==>
		{ 
			char *ename;
			const_str_t evalue;
			reg_t a;
			reg_t b;

			Comment2( ine.. , $1, $2 );
			a= alloc_reg();
			b= alloc_reg();

			ename= $1;
			sprint(evalue, "%d", $2);
			"sethi	%hi($ename+$evalue), $a";
			"ld	[$a+%lo($ename+$evalue)], $b";
			"inc	$b";
			"st	$b, [$a+%lo($ename+$evalue)]"
			free_reg(a);
			free_reg(b);
		}.


C_dec		==>
			Comment0( dec );
			inc_tos(-1).

C_del		==>
		Comment( del , $1 );
		{
			reg_t S1;

			if (S1 = find_local($1, NULL)) {
				change_reg(S1);
				"dec	1, $S1";
			} else {
				soft_alloc_reg(reg_lb);
				push_reg(reg_lb);
				inc_tos($1);
				C_loi(4);
				C_dec();
				soft_alloc_reg(reg_lb);
				push_reg(reg_lb);
				inc_tos($1);
				C_sti(4);
			}
		}.

C_dee..		==>
		{ 
			char *ename;
			const_str_t evalue;
			reg_t a;
			reg_t b;

			Comment2( dee.. , $1, $2 );
			a= alloc_reg();
			b= alloc_reg();

			ename= $1;
			sprint(evalue, "%d", $2);
			"sethi	%hi($ename+$evalue), $a";
			"ld	[$a+%lo($ename+$evalue)], $b";
			"dec	$b";
			"st	$b, [$a+%lo($ename+$evalue)]"
			free_reg(a);
			free_reg(b);
		}.

C_zrl		==>
		Comment( zrl , $1 );
		{
			reg_t S1;

			if (S1 = find_local($1, NULL)) {
				change_reg(S1);
				"mov	0, $S1";
			} else {
				push_const(0);
				soft_alloc_reg(reg_lb);
				push_reg(reg_lb);
				inc_tos($1);
				C_sti(4);
			}
		}.

C_zre..		==>
		{ 
			char *ename;
			const_str_t evalue;
			reg_t a;

			Comment2( zre.. , $1, $2 );
			a= alloc_reg();

			ename= $1;
			sprint(evalue, "%d", $2);
			"sethi	%hi($ename+$evalue), $a";
			"st	%g0, [$a+%lo($ename+$evalue)]"
			free_reg(a);
		}.

C_zrf 		==>
			Comment( zrf , $1 );
			push_const($1);
			C_zrf_narg().

C_zrf_narg	==>
			Comment0( zrf_narg );
			C_zer_narg().


C_zer		==>
			Comment( zer, $1);
			push_const($1);
			C_zer_narg().

C_zer_narg	==>
	{
		reg_t a;
		int n;
		const_str_t n_str;

		Comment0( zer_narg);

		if (type_of_tos() == T_cst && top_const() <= 8)
		{
			n= pop_const(n_str);
			if (n == 4)
				push_const(0);
			else if (n == 8)
			{
				push_const(0);
				push_const(0);
			}
			else
				arg_error ("zer", n);
		}
		else
		{
			a= pop_reg();
			flush_cache();
			"sub	$reg_sp, $a, $reg_sp";
		"1:"
			"deccc	4, $a";		/* hack */
			"st	%g0, [$reg_sp+$a]";
			"bne	1b";
			"nop";
			free_reg(a);
		}
	}.

/******************************************************************************/
/*									      */
/*		Group 8 : Convert 					      */
/*									      */
/******************************************************************************/

/* cii, ciu, cuu, cui are assumed to be called with legal arguments only */

C_cii		==>
	{
		reg_t a;	/* target obj size */
		reg_t b;	/* src obj size */
		int n1;		/* target obj size */
		int n2; 	/* src obj size */
		const_str_t n1_str;

		Comment0( cii );
		a= NULL;
		b= NULL;

		if (type_of_tos() != T_cst)
		{
			a= pop_reg();
			b= pop_reg();
		}
		else
		{
			n1= pop_const(n1_str);
			if (type_of_tos() != T_cst)
			{
				a= alloc_reg();
				"set	$n1_str, $a";
				b= pop_reg();
			}
			else
				n2= pop_const(NULL);
		}

		if (!a)
		{
			a = pop_reg();
			if (n1 > EM_WSIZE)
				arg_error ("unimp cii", n1);
			if (n2 > EM_WSIZE)
				arg_error ("unimp cii", n2);
			if (n2 < EM_WSIZE) {
				b = alloc_reg();
				if (n2 == 1)
				{
					"sll	$a, 24, $b";
					"sra	$b, 24, $b";
				}
				else if (n2 == 2)
				{
					"sll	$a, 16, $b";
					"sra	$b, 16, $b";
				}
				free_reg(a);
				push_reg(b);
			}
			else
				push_reg(a);
		} else {
			flush_cache();
			"cmp	$a, $b";
			"ble	4f";
			"nop";			/* delay slot */
			"cmp	$b, 1";
			"bne	2f";
			"nop";			/* delay slot */
		"1:";
			"b	3f";
			"ldsb	[$reg_sp+3], $a";	/* delay slot */
		"2:"
			"ldsh	[$reg_sp+2], $a";
		"3:";
			"st	$a, [$reg_sp]";
		"4:";
			free_reg(a);
			free_reg(b);
		}
	}.


C_cuu		==>
			Comment0( cuu  );
		 	pop_nop(2).

C_ciu		==>
			Comment0( ciu );
		 	pop_nop(2).

C_cui		==>
			Comment0( cui );
		 	pop_nop(2).

C_cfi		==>
	{
		reg_t a;	/* target (int) size */
		reg_t b;	/* src (float) size */
		reg_t s1;
		reg_t s2;
		reg_t d1;
		reg_t d2;
		int n1;		/* target (int) size */
		int n2;		/* src (float) size */
		const_str_t n1_str;

		Comment0( cfi );
		a= NULL;
		b= NULL;
		if (type_of_tos() != T_cst)
		{
			a= pop_reg();
			b= pop_reg();
		}
		else
		{
			n1= pop_const (n1_str);
			if (type_of_tos() != T_cst)
			{
				a= alloc_reg();
				"set	$n1_str, $a";
				b= pop_reg();
			}
			else
				n2= pop_const(NULL);
		}

		if (!a)
		{
			if (n1 != EM_WSIZE)
				arg_error ("unimp cfi", n1);
			if (n2 == EM_WSIZE)
			{
				s1= pop_float();
				d1= alloc_float();
				"fstoi	$s1, $d1";
				free_reg(s1);
				push_reg(d1);
			}
			else if (n2 == EM_DSIZE)
			{
				s1= pop_double(NULL);
				d1= alloc_float();
				"fdtoi	$s1, $d1";
				free_double_reg(s1);
				push_reg(d1);
			}
			else
				arg_error ("unimp cfi", n2);
		}
		else
		{

			d1= alloc_float();
			flush_cache();
			force_alloc_output();
			"cmp	$a, 4";
			"bne	0f";
			"nop";
			"cmp	$b, 4";
			"be	4f";
			"nop";
			"cmp	$b, 8";
			"bne	0f";
			"nop";
		"8:";
			"ld	[$reg_sp], %f0";
			"ld	[$reg_sp+STACK_CLICK], %f1";
			"fdtoi	%f0, $d1";
			"b	1f";
			"inc	2*STACK_CLICK, $reg_sp"; /* delay slot */
		"4:";
			"ld	[$reg_sp+2*STACK_CLICK], %f0";
			"fstoi	%f0, $d1";
			"b	1f";
			"inc	STACK_CLICK, $reg_sp"; /* delay slot */
		"0:";
			"set	E_EM_CFI, %o0";
			"call	trp";
			"nop";
		"1:";
			free_reg(a);
			free_reg(b);
			push_reg(d1);
			free_output();
		}
	}.

C_cfu		==>
	{
		reg_t a;	/* target (int) size */
		reg_t b;	/* src (float) size */
		int n1;		/* target (int) size */
		int n2;		/* src (float) size */
		const_str_t n1_str;

		Comment0( cfu );
		a= NULL;
		b= NULL;
		if (type_of_tos() != T_cst)
		{
			a= pop_reg();
			b= pop_reg();
		}
		else
		{
			n1= pop_const (n1_str);
			if (type_of_tos() != T_cst)
			{
				a= alloc_reg();
				"set	$n1_str, $a";
				b= pop_reg();
			}
			else
				n2= pop_const(NULL);
		}

		if (!a)
		{
			if (n1 != EM_WSIZE)
				arg_error ("unimp cfu", n1);
			force_alloc_output();
			flush_cache();
			if (n2 == EM_WSIZE)
			{
				"call cfu4";
				"nop";
			}
			else if (n2 == EM_DSIZE)
			{
				"call cfu8";
				"nop";
			}
			else
				arg_error ("unimp cfu", n2);
			soft_alloc_reg(reg_o0);
			free_output();
			push_reg(reg_o0);
		}
		else
		{
			flush_cache();
			force_alloc_output();
			"cmp	$a, 4";
			"bne	0f";
			"nop";
			"cmp	$b, 4";
			"be	4f";
			"nop";
			"cmp	$b, 8";
			"bne	0f";
			"nop";
		"8:";
			"call	cfu8";
			"nop";
			"b	1f";
		"4:";
			"call	cfu4";
			"nop";
			"b	1f";
		"0:";
			"set	E_EM_CFU, %o0";
			"call	trp";
			"nop";
		"1:";
			free_reg(a);
			free_reg(b);
			soft_alloc_reg(reg_o0);
			free_output();
			push_reg(reg_o0);
		}
	}.

C_cff		==>
	{
		reg_t a;	/* target (int) size */
		reg_t b;	/* src (float) size */
		int n1;		/* target (int) size */
		int n2;		/* src (float) size */
		const_str_t n1_str;

		Comment0( cff );
		a= NULL;
		b= NULL;
		if (type_of_tos() != T_cst)
		{
			a= pop_reg();
			b= pop_reg();
		}
		else
		{
			n1= pop_const (n1_str);
			if (type_of_tos() != T_cst)
			{
				a= alloc_reg();
				"set	$n1_str, $a";
				b= pop_reg();
			}
			else
				n2= pop_const(NULL);
		}

		if (!a)
		{
			if (n1 == EM_WSIZE)
			{
				if (n2 == EM_DSIZE)
				{
					a= pop_double(NULL);
					b= alloc_float();
					"fdtos	$a, $b";
					free_double_reg(a);
					push_reg(b);
				} else if (n2 != EM_WSIZE)
					arg_error ("unimp cff", n2);
			}
			else if (n1 == EM_DSIZE)
			{
				if (n2 == EM_WSIZE)
				{
					a= pop_float();
					b= alloc_double(NULL);
					"fstod	$a, $b";
					free_reg(a);
					push_double_reg(b);
				} else if (n2 != EM_DSIZE)
					arg_error ("unimp cff", n2);
			}
			else
				arg_error ("unimp cff", n1);
		}
		else
		{

			flush_cache();
			force_alloc_output();
			"cmp	$b, $a";
			"be	1f";
			"nop";		/* delay slot */
			"cmp	$b, 4";
			"be	4f";
			"nop";
			"cmp	$b, 8";
			"be	8f";
			"nop";
		"0:"
			"set	E_EM_CFF, %o0";
			"call	trp";
			"nop";
		"4:";
			"cmp	$a, 8";
			"bne	0b";
			"nop";
			"ld	[$reg_sp], %f0";
			"fstod	%f0, %f2";
			"dec	STACK_CLICK, $reg_sp";
			"st	%f2, [$reg_sp]";
			"st	%f3, [$reg_sp+STACK_CLICK]";
			"b	1f";
			"nop";
		"8:";
			"cmp	$a, 4";
			"bne	0b";
			"nop";
			"ld	[$reg_sp], %f0";
			"ld	[$reg_sp+STACK_CLICK], %f1";
			"fdtos	%f0, %f2";
			"inc	STACK_CLICK, $reg_sp";
			"st	%f2, [$reg_sp]";
		"1:";
			free_reg(a);
			free_reg(b);
			free_output();
		}
	}.

C_cif		==>
	{
		reg_t a;	/* target (float) size */
		reg_t b;	/* src (int) size */
		int n1;		/* target (float) size */
		int n2;		/* src (int) size */
		reg_t r1;
		reg_t f1;
		const_str_t n1_str;

		Comment0( cif );
		a= NULL;
		b= NULL;
		if (type_of_tos() != T_cst)
		{
			a= pop_reg();
			b= pop_reg();
		}
		else
		{
			n1= pop_const (n1_str);
			if (type_of_tos() != T_cst)
			{
				a= alloc_reg();
				"set	$n1_str, $a";
				b= pop_reg();
			}
			else
				n2= pop_const(NULL);
		}

		if (!a)
		{
			if (n2 != EM_WSIZE)
				arg_error ("unimp cif", n2);
			else
			{
				if (n1 == EM_WSIZE)
				{
					r1= pop_float();
					f1= alloc_float();
					"fitos	$r1, $f1";
					free_reg(r1);
					push_reg(f1);

				}
				else if (n1 == EM_DSIZE)
				{
					r1= pop_float();
					f1= alloc_double(NULL);
					"fitod	$r1, $f1";
					free_reg(r1);
					push_double_reg(f1);
				}
				else
					arg_error ("unimp cif", n1);
			}
		}
		else
		{
			flush_cache();
			force_alloc_output();
			"cmp	$a, 4";
			"be	4f";
			"nop";		/* delay slot */
			"cmp	$a, 8";
			"be	8f";
			"nop";		/* delay slot */
		"1:"
			"set	E_EM_CUF, %o0";
			"call	trp";
			"nop";
		"4:";
			"cmp	$b, 4";
			"bne	1b";
			"nop";		/* delay slot */
			"ld	[$reg_sp], %f0";
			"fitos	%f0, %f1";
			"b	0f";
			"st	%f1, [$reg_sp]";	/* delay slot */
		"8:";
			"dec	STACK_CLICK, $reg_sp";
			"cmp	$b, 4";
			"bne	1b";
			"nop";		/* delay slot */
			"ld	[$reg_sp+STACK_CLICK], %f0";
			"fitod	%f0, %f2";
			"st	%f2, [$reg_sp]";
			"b	0f";
			"st	%f3, [$reg_sp+STACK_CLICK]"; /* delay slot */
		"0:";
			free_reg(a);
			free_reg(b);
			free_output();
		}
	}.


C_cuf		==>
	{
		reg_t a;	/* target (float) size */
		reg_t b;	/* src (int) size */
		reg_t c;
		reg_t fs1;
		reg_t fs2;
		reg_t fd1;
		reg_t fd2;
		int n1;		/* target (float) size */
		int n2;		/* src (int) size */
		const_str_t n1_str;

		Comment0( cuf );
		a= NULL;
		b= NULL;
		if (type_of_tos() != T_cst)
		{
			a= pop_reg();
			b= pop_reg();
		}
		else
		{
			n1= pop_const (n1_str);
			if (type_of_tos() != T_cst)
			{
				a= alloc_reg();
				"set	$n1_str, $a";
				b= pop_reg();
			}
			else
				n2= pop_const(NULL);
		}

		if (!a)
		{
			if (n2 != EM_WSIZE)
				arg_error ("unimp cuf", n2);
			else
			{
				if (n1 == EM_WSIZE)
				{
					fs1= pop_float();
					fs2= alloc_float();
					a= alloc_reg();
					"fitos	$fs1, $fs2";
					"sethi	%hi(Fs0), $a";
					"ld	[$a+%lo(Fs0)], $fs1";
					"fcmpes	$fs2, $fs1";
					"nop";
					"fbge	0f";
					"nop";
					"sethi	%hi(Fs80000000), $a";
					"ld	[$a+%lo(Fs80000000)], $fs1";
					"fadds	$fs1, $fs2, $fs2";
				"0:";
					push_reg(fs2);
					free_reg(fs1);
					free_reg(a);
				}
				else if (n1 == EM_DSIZE)
				{
					fs1= pop_float();
					fd1= alloc_double(NULL);
					fd2= alloc_double(NULL);
					a= alloc_reg();
					"fitod	$fs1, $fd2";
					"sethi	%hi(Fd0), $a";
					"ldd	[$a+%lo(Fd0)], $fd1";
					"fcmped	$fd2, $fd1";
					"nop";
					"fbge	0f";
					"nop";
					"sethi	%hi(Fd80000000), $a";
					"ldd	[$a+%lo(Fd80000000)], $fd1";
					"faddd	$fd1, $fd2, $fd2";
				"0:";
					free_reg(fs1);
					free_double_reg(fd1);
					push_double_reg(fd2);
					free_reg(a);
				}
				else
					arg_error ("unimp cuf", n1);
			}
		}
		else
		{
#if 0
			flush_cache();

			"cmp	$a, 4";
			"be	4f";
			"nop";		/* delay slot */
			"cmp	$a, 8";
			"be	8f";
			"nop";		/* delay slot */
		"1:"
			"set	E_EM_CUF, %o0";
			"set	fatal, %g1";
			"jmp	%g1";
			"nop";
		"4:";
			"cmp	$b, 4";
			"bne	1b";
			"nop";		/* delay slot */
			"ld	[$reg_sp], $c";
			"tst	$c";
			"bl	5f";
			"nop";		/* delay slot */
			"ld	[$reg_sp], %f0";
			"fitos	%f0, %f1";
			"b	0f";
			"st	%f1, [$reg_sp]";	/* delay slot */
		"5:";
			"set	MAX_INT, $b";
			"sub	$c, $b, $a";
			"st	$a, [$reg_sp]";
			"ld	[$reg_sp], %f0";
			"st	$b, [$reg_sp]";
			"ld	[$reg_sp], %f1";
			"fitos	%f0, %f2";
			"fitos	%f1, %f3";
			"fadds	%f2, %f3, %f0";
			"b	0f";
			"st	%f0, [$reg_sp]";		/* delay slot */
		"8:";
			"dec	STACK_CLICK, $reg_sp";
			"cmp	$b, 4";
			"bne	1b";
			"nop";		/* delay slot */
			"ld	[$reg_sp+STACK_CLICK], $c";
			"tst	$c";
			"bl	9f";
			"nop";		/* delay slot */
			"ld	[$reg_sp+STACK_CLICK], %f0";
			"fitod	%f0, %f2";
			"st	%f2, [$reg_sp]";
			"b	0f";
			"st	%f3, [$reg_sp+STACK_CLICK]";	/* delay slot */
		"9:";
			"set	MAX_INT, $b";
			"sub	$c, $b, $a";
			"st	$a, [$reg_sp+STACK_CLICK]";
			"ld	[$reg_sp+STACK_CLICK], %f0";
			"st	$b, [$reg_sp+STACK_CLICK]";
			"ld	[$reg_sp+STACK_CLICK], %f1";
			"fitod	%f0, %f2";
			"fitod	%f1, %f4";
			"fadds	%f2, %f4, %f0";
			"st	%f0, [$reg_sp]";
			"b	0f";
			"st	%f1, [$reg_sp+STACK_CLICK]";	/* delay slot */
		"0:";
			free_reg(a);
			free_reg(b);
			free_reg(c);
#else
	not_implemented ("cuf");
#endif
		}
	}.
/******************************************************************************/
/*									      */
/*		Group 9 : Logical 	 				      */
/*									      */
/******************************************************************************/

C_and		==>
	Comment( and, $1);
	push_const($1);
	C_and_narg().

C_and_narg	==>
	{
		reg_t a;
		reg_t b;
		reg_t c;
		reg_t d;
		reg_t e;
		reg_t f;
		const_str_t a_cst_str;
		const_str_t b_cst_str;
		const_str_t c_cst_str;
		const_str_t d_cst_str;
		int n;
		const_str_t n_str;

		Comment0( and_narg );
		if (type_of_tos() == T_cst)
		{
			n= pop_const(n_str);
			if (n == EM_WSIZE)
			{
				if (type_of_tos() == T_cst && const13(top_const()))
				{
					a= NULL;
					pop_const (a_cst_str);
				}
				else
					a= pop_reg();
				if (type_of_tos() == T_cst && const13(top_const()))
				{
					b= NULL;
					pop_const (b_cst_str);
				}
				else
					b= pop_reg();
				if (!a && !b)
				{
					a= alloc_reg();
					"mov	$a_cst_str, $a";	
				}
				c= alloc_reg();
				if (a)
					if (b)
						"and	$a, $b, $c";
					else
						"and	$a, $b_cst_str, $c";
				else
					"and	$b, $a_cst_str, $c";
				free_reg(a);
				free_reg(b);
				push_reg(c);
			}
			else if (n == EM_DSIZE)
			{
				if (type_of_tos() == T_cst && const13(top_const()))
				{
					a= NULL;
					pop_const (a_cst_str);
				}
				else
					a= pop_reg();
				if (type_of_tos() == T_cst && const13(top_const()))
				{
					b= NULL;
					pop_const (b_cst_str);
				}
				else
					b= pop_reg();
				if (type_of_tos() == T_cst && const13(top_const()))
				{
					c= NULL;
					pop_const (c_cst_str);
				}
				else
					c= pop_reg();
				if (type_of_tos() == T_cst && const13(top_const()))
				{
					d= NULL;
					pop_const (d_cst_str);
				}
				else
					d= pop_reg();
				if (!b && !d)
				{
					b= alloc_reg();
					"mov	$b_cst_str, $b";	
				}
				e= alloc_reg();
				if (b)
					if (d)
						"and	$b, $d, $e";
					else
						"and	$b, $d_cst_str, $e";
				else
					"and	$d, $b_cst_str, $e";
				free_reg(b);
				free_reg(d);
				push_reg(e);
				if (!a && !c)
				{
					a= alloc_reg();
					"mov	$a_cst_str, $a";	
				}
				e= alloc_reg();
				if (a)
					if (c)
						"and	$a, $c, $e";
					else
						"and	$a, $c_cst_str, $e";
				else
					"and	$c, $a_cst_str, $e";
				free_reg(a);
				free_reg(c);
				push_reg(e);
			}
			else if (!(n % EM_WSIZE))
			{
				a= alloc_reg();
				b= alloc_reg();
				c= alloc_reg();
				d= alloc_reg();
				e= alloc_reg();
				f= alloc_reg();
				flush_cache();

				"set	$n_str, $a";
				"add	$reg_sp, $a, $b";
				"mov	$a, $c";
			"1:";
				"deccc	4, $c";
				"ld	[$reg_sp+$c], $d";
				"ld	[$b+$c], $e";
				"and	$d, $e, $f";
				"bnz	1b";
				"st	$f, [$b+$c]";	/* delay slot */
				"add	$reg_sp, $a, $reg_sp";
				free_reg(a);
				free_reg(b);
				free_reg(c);
				free_reg(d);
				free_reg(e);
				free_reg(f);
			}
			else
				arg_error ("unimp and", n);
		}
		else
		{
			a= pop_reg();
			b= alloc_reg();
			c= alloc_reg();
			d= alloc_reg();
			e= alloc_reg();
			f= alloc_reg();
			flush_cache();

			"add	$reg_sp, $a, $b";
			"mov	$a, $c";
		"1:";
			"deccc	4, $c";
			"ld	[$reg_sp+$c], $d";
			"ld	[$b+$c], $e";
			"and	$d, $e, $f";
			"bnz	1b";
			"st	$f, [$b+$c]";	/* delay slot */
			"add	$reg_sp, $a, $reg_sp";
			free_reg(a);
			free_reg(b);
			free_reg(c);
			free_reg(d);
			free_reg(e);
			free_reg(f);
			
		}
	}.

C_ior		==>
	Comment( ior, $1);
	push_const($1);
	C_ior_narg().

C_ior_narg	==>
	{
		reg_t a;
		reg_t b;
		reg_t c;
		reg_t d;
		reg_t e;
		reg_t f;
		const_str_t a_cst_str;
		const_str_t b_cst_str;
		const_str_t c_cst_str;
		const_str_t d_cst_str;
		int n;
		const_str_t n_str;

		Comment0( ior_narg );
		if (type_of_tos() == T_cst)
		{
			n= pop_const(n_str);
			if (n == EM_WSIZE)
			{
				if (type_of_tos() == T_cst && const13(top_const()))
				{
					a= NULL;
					pop_const (a_cst_str);
				}
				else
					a= pop_reg();
				if (type_of_tos() == T_cst && const13(top_const()))
				{
					b= NULL;
					pop_const (b_cst_str);
				}
				else
					b= pop_reg();
				if (!a && !b)
				{
					a= alloc_reg();
					"mov	$a_cst_str, $a";	
				}
				c= alloc_reg();
				if (a)
					if (b)
						"or	$a, $b, $c";
					else
						"or	$a, $b_cst_str, $c";
				else
					"or	$b, $a_cst_str, $c";
				free_reg(a);
				free_reg(b);
				push_reg(c);
			}
			else if (n == EM_DSIZE)
			{
				if (type_of_tos() == T_cst && const13(top_const()))
				{
					a= NULL;
					pop_const (a_cst_str);
				}
				else
					a= pop_reg();
				if (type_of_tos() == T_cst && const13(top_const()))
				{
					b= NULL;
					pop_const (b_cst_str);
				}
				else
					b= pop_reg();
				if (type_of_tos() == T_cst && const13(top_const()))
				{
					c= NULL;
					pop_const (c_cst_str);
				}
				else
					c= pop_reg();
				if (type_of_tos() == T_cst && const13(top_const()))
				{
					d= NULL;
					pop_const (d_cst_str);
				}
				else
					d= pop_reg();
				if (!b && !d)
				{
					b= alloc_reg();
					"mov	$b_cst_str, $b";	
				}
				e= alloc_reg();
				if (b)
					if (d)
						"or	$b, $d, $e";
					else
						"or	$b, $d_cst_str, $e";
				else
					"or	$d, $b_cst_str, $e";
				free_reg(b);
				free_reg(d);
				push_reg(e);
				if (!a && !c)
				{
					a= alloc_reg();
					"mov	$a_cst_str, $a";	
				}
				e= alloc_reg();
				if (a)
					if (c)
						"or	$a, $c, $e";
					else
						"or	$a, $c_cst_str, $e";
				else
					"or	$c, $a_cst_str, $e";
				free_reg(a);
				free_reg(c);
				push_reg(e);
			}
			else if (!(n % EM_WSIZE))
			{
				a= alloc_reg();
				b= alloc_reg();
				c= alloc_reg();
				d= alloc_reg();
				e= alloc_reg();
				f= alloc_reg();
				flush_cache();

				"set	$n_str, $a";
				"add	$reg_sp, $a, $b";
				"mov	$a, $c";
			"1:";
				"deccc	4, $c";
				"ld	[$reg_sp+$c], $d";
				"ld	[$b+$c], $e";
				"or	$d, $e, $f";
				"bnz	1b";
				"st	$f, [$b+$c]";	/* delay slot */
				"add	$reg_sp, $a, $reg_sp";
				free_reg(a);
				free_reg(b);
				free_reg(c);
				free_reg(d);
				free_reg(e);
				free_reg(f);
			}
			else
				arg_error ("unimp ior", n);
		}
		else
		{
			a= pop_reg();
			b= alloc_reg();
			c= alloc_reg();
			d= alloc_reg();
			e= alloc_reg();
			f= alloc_reg();
			flush_cache();

			"add	$reg_sp, $a, $b";
			"mov	$a, $c";
		"1:";
			"deccc	4, $c";
			"ld	[$reg_sp+$c], $d";
			"ld	[$b+$c], $e";
			"or	$d, $e, $f";
			"bnz	1b";
			"st	$f, [$b+$c]";	/* delay slot */
			"add	$reg_sp, $a, $reg_sp";
			free_reg(a);
			free_reg(b);
			free_reg(c);
			free_reg(d);
			free_reg(e);
			free_reg(f);
		}
	}.



C_xor		==>
	Comment( xor, $1);
	push_const($1);
	C_xor_narg().

C_xor_narg	==>
	{
		reg_t a;
		reg_t b;
		reg_t c;
		reg_t d;
		reg_t e;
		reg_t f;
		const_str_t a_cst_str;
		const_str_t b_cst_str;
		const_str_t c_cst_str;
		const_str_t d_cst_str;
		int n;
		const_str_t n_str;

		Comment0( xor_narg );
		if (type_of_tos() == T_cst)
		{
			n= pop_const(n_str);
			if (n == EM_WSIZE)
			{
				if (type_of_tos() == T_cst && const13(top_const()))
				{
					a= NULL;
					pop_const (a_cst_str);
				}
				else
					a= pop_reg();
				if (type_of_tos() == T_cst && const13(top_const()))
				{
					b= NULL;
					pop_const (b_cst_str);
				}
				else
					b= pop_reg();
				if (!a && !b)
				{
					a= alloc_reg();
					"mov	$a_cst_str, $a";	
				}
				c= alloc_reg();
				if (a)
					if (b)
						"xor	$a, $b, $c";
					else
						"xor	$a, $b_cst_str, $c";
				else
					"xor	$b, $a_cst_str, $c";
				free_reg(a);
				free_reg(b);
				push_reg(c);
			}
			else if (n == EM_DSIZE)
			{
				if (type_of_tos() == T_cst && const13(top_const()))
				{
					a= NULL;
					pop_const (a_cst_str);
				}
				else
					a= pop_reg();
				if (type_of_tos() == T_cst && const13(top_const()))
				{
					b= NULL;
					pop_const (b_cst_str);
				}
				else
					b= pop_reg();
				if (type_of_tos() == T_cst && const13(top_const()))
				{
					c= NULL;
					pop_const (c_cst_str);
				}
				else
					c= pop_reg();
				if (type_of_tos() == T_cst && const13(top_const()))
				{
					d= NULL;
					pop_const (d_cst_str);
				}
				else
					d= pop_reg();
				if (!b && !d)
				{
					b= alloc_reg();
					"mov	$b_cst_str, $b";	
				}
				e= alloc_reg();
				if (b)
					if (d)
						"xor	$b, $d, $e";
					else
						"xor	$b, $d_cst_str, $e";
				else
					"xor	$d, $b_cst_str, $e";
				free_reg(b);
				free_reg(d);
				push_reg(e);
				if (!a && !c)
				{
					a= alloc_reg();
					"mov	$a_cst_str, $a";	
				}
				e= alloc_reg();
				if (a)
					if (c)
						"xor	$a, $c, $e";
					else
						"xor	$a, $c_cst_str, $e";
				else
					"xor	$c, $a_cst_str, $e";
				free_reg(a);
				free_reg(c);
				push_reg(e);
			}
			else if (!(n % EM_WSIZE))
			{
				a= alloc_reg();
				b= alloc_reg();
				c= alloc_reg();
				d= alloc_reg();
				e= alloc_reg();
				f= alloc_reg();
				flush_cache();

				"set	$n_str, $a";
				"add	$reg_sp, $a, $b";
				"mov	$a, $c";
			"1:";
				"deccc	4, $c";
				"ld	[$reg_sp+$c], $d";
				"ld	[$b+$c], $e";
				"xor	$d, $e, $f";
				"bnz	1b";
				"st	$f, [$b+$c]";	/* delay slot */
				"add	$reg_sp, $a, $reg_sp";
				free_reg(a);
				free_reg(b);
				free_reg(c);
				free_reg(d);
				free_reg(e);
				free_reg(f);
			}
			else
				arg_error ("unimp xor", n);
		}
		else
		{
			a= pop_reg();
			b= alloc_reg();
			c= alloc_reg();
			d= alloc_reg();
			e= alloc_reg();
			f= alloc_reg();
			flush_cache();

			"add	$reg_sp, $a, $b";
			"mov	$a, $c";
		"1:";
			"deccc	4, $c";
			"ld	[$reg_sp+$c], $d";
			"ld	[$b+$c], $e";
			"xor	$d, $e, $f";
			"bnz	1b";
			"st	$f, [$b+$c]";	/* delay slot */
			"add	$reg_sp, $a, $reg_sp";
			free_reg(a);
			free_reg(b);
			free_reg(c);
			free_reg(d);
			free_reg(e);
			free_reg(f);
		}
	}.



C_com		==>
	Comment( com, $1);
	push_const($1);
	C_com_narg().

C_com_narg	==>
	{
		reg_t a;
		reg_t b;
		reg_t c;
		reg_t d;
		int n;
		int i;
		const_str_t i_str;

		Comment0( com_narg );
		if (type_of_tos() == T_cst && top_const() <= MAX_UNROLL)
		{
			n= pop_const(NULL);
			if (n == 4)
			{
				a= pop_reg();
				b= alloc_reg();
				"not	$a, $b";
				free_reg(a);
				push_reg(b);
			}
			else if (n == 8)
			{
				a= pop_reg();
				b= pop_reg();
				c= alloc_reg();
				d= alloc_reg();
				"not	$a, $c";
				"not	$b, $d";
				push_reg(d);
				push_reg(c);
				free_reg(b);
				free_reg(a);
			}
			else if (n>0 && !(n % 4))
			{
				flush_cache();
				a= alloc_reg();
				b= alloc_reg();
				for (i= 0; i< n; i += 4)
				{
					sprint(i_str, "%d", i);
					"ld	[$reg_sp+$i_str], $a";
					"not	$a, $b";
					"st	$b, [$reg_sp+$i_str]";
				}
			}
			else
				arg_error ("com", n);
		}
		else
		{
			a= pop_reg();
			b= alloc_reg();
			c= alloc_reg();
			flush_cache();
		"1:";
			"deccc	4, $a";
			"ld	[$reg_sp+$a], $b";
			"not	$a, $c";
			"bnz	1b";
			"st	$c, [$reg_sp+$a";
			free_reg(a);
			free_reg(b);
			free_reg(c);
		}
	}.

C_rol
	$1 == 4		==>
	{
		reg_t a;
		reg_t b;
		reg_t c;
		reg_t d;
		int n;
		const_str_t n_str;

		Comment( rol, $1);

		if (type_of_tos() == T_cst)
		{
			n= pop_const(NULL);
			if (n<0)
				arg_error("rol 4:", n);
			else
			{
				n= n % 32;
				if (n)
				{
					a= pop_reg();
					b= alloc_reg();
					c= alloc_reg();
					sprint(n_str, "%d", n);
					"sll	$a, $n_str, $b";
					sprint(n_str, "%d", 32-n);
					"srl	$a, $n_str, $c";
					"or	$b, $c, $a";
					push_reg(a);
					free_reg(b);
					free_reg(c);
				}
			}
		}
		else
		{
			a= pop_reg();
			b= pop_reg();
			c= alloc_reg();
			d= alloc_reg();
			"and	$a, 31, $c";
			"mov	32, $a";
			"sub	$a, $c, $d";
			"sll	$b, $c, $a";
			"srl	$b, $d, $c";
			"or	$a, $c, $b";
			free_reg(a);
			push_reg(b);
			free_reg(c);
			free_reg(d);
		}
	}.
	default		==>
				arg_error( "rol", $1).

narg4(rol)

C_ror
	$1 == 4		==>
	{
		reg_t a;
		reg_t b;
		reg_t c;
		reg_t d;
		int n;
		const_str_t n_str;

		Comment( ror, $1);

		if (type_of_tos() == T_cst)
		{
			n= pop_const(NULL);
			if (n<0)
				arg_error("ror 4:", n);
			else
			{
				n= n % 32;
				if (n)
				{
					a= pop_reg();
					b= alloc_reg();
					c= alloc_reg();
					sprint(n_str, "%d", n);
					"srl	$a, $n_str, $b";
					sprint(n_str, "%d", 32-n);
					"sll	$a, $n_str, $c";
					"or	$b, $c, $a";
					push_reg(a);
					free_reg(b);
					free_reg(c);
				}
			}
		}
		else
		{
			a= pop_reg();
			b= pop_reg();
			c= alloc_reg();
			d= alloc_reg();
			"and	$a, 31, $c";
			"mov	32, $a";
			"sub	$a, $c, $d";
			"srl	$b, $c, $a";
			"sll	$b, $d, $c";
			"or	$a, $c, $b";
			free_reg(a);
			push_reg(b);
			free_reg(c);
			free_reg(d);
		}
	}.
	default		==>
				arg_error( "ror", $1).

narg4(ror)

/******************************************************************************/
/*									      */
/*		Group 10 : Sets 	 				      */
/*									      */
/******************************************************************************/

C_inn		==>
	Comment( inn, $1);
	push_const($1);
	C_inn_narg().

C_inn_narg	==>
	{
		reg_t a;
		reg_t b;
		reg_t c;
		reg_t d;
		int i;
		int n;
		const_str_t i_str;
		const_str_t n_str;

		Comment0(inn_narg);
		if (type_of_tos() == T_cst && const13(top_const()))
		{
			n= pop_const(n_str);
			if (n == EM_WSIZE)
			{
				if (type_of_tos() == T_cst)
				{
					i= pop_const (i_str);
					if (i >= n*8)
						push_const(0);
					else
					{
						a= pop_reg();
						b= alloc_reg();
						c= alloc_reg();
						"srl	$a, $i_str, $b";
						"and	$b, 1, $c";
						free_reg(a);
						free_reg(b);
						push_reg(c);
					}
				}
				else
				{
					a= pop_reg();
					b= pop_reg();
					c= alloc_reg();
					"srl	$b, $a, $c";
					"and	$c, 1, $a";
					push_reg(a);
					free_reg(b);
					free_reg(c);
				}
			}
			else if (n == 2*EM_WSIZE)
			{
				if (type_of_tos() == T_cst)
				{
					i= pop_const (i_str);
					if (i >= n*8)
						push_const(0);
					else
					{
						if (i>= EM_WSIZE*8)
						{
							i -= EM_WSIZE*8;
							pop_nop(1);
							a= pop_reg();
						}
						else
						{
							a= pop_reg();
							pop_nop(1);
						}
						b= alloc_reg();
						c= alloc_reg();
						"srl	$a, $i_str, $b";
						"and	$b, 1, $c";
						free_reg(a);
						free_reg(b);
						push_reg(c);
					}
				}
				else
				{
					a= pop_reg();
					flush_cache();
					b= alloc_reg();
					c= alloc_reg();
					d= alloc_reg();
					flush_cache();
					"andn	$a, 31, $b";
					"and	$a, 31, $c";
					"srl	$b, 3, $d";
					"ld	[$reg_sp+$d], $b";
					"inc	$n_str, $reg_sp";
					"srl	$b, $c, $d";
					"and	$d, 1, $b";
					free_reg(a);
					push_reg(b);
					free_reg(c);
					free_reg(d);
				}
			}
			else if (n % EM_WSIZE)
				arg_error ("inn", n);
			else
			{
				a= pop_reg();
				flush_cache();
				b= alloc_reg();
				c= alloc_reg();
				d= alloc_reg();
				flush_cache();
				"andn	$a, 31, $b";
				"and	$a, 31, $c";
				"srl	$b, 3, $d";
				"ld	[$reg_sp+$d], $b";
				"inc	$n_str, $reg_sp";
				"srl	$b, $c, $d";
				"and	$d, 1, $b";
				free_reg(a);
				push_reg(b);
				free_reg(c);
				free_reg(d);
			}
		}
		else
			not_implemented ("inn_narg");
	}.

C_set	==>	Comment( set, $1);
		push_const($1);
		C_set_narg().

C_set_narg	==>
	{
		reg_t a;
		reg_t b;
		reg_t c;
		reg_t d;
		int n;
		const_str_t n_str;

		Comment0( set_narg );

		if (type_of_tos() == T_cst) {
			n = pop_const(n_str);
			if (n == EM_WSIZE) {
				b = alloc_reg();
				c = alloc_reg();
				a = pop_reg();
				"set	1, $c";
				"sll	$c, $a, $b";
				free_reg(a);
				free_reg(c);
				push_reg(b);
			} else {
				a= alloc_reg();
				b= pop_reg();
				c= alloc_reg();
				d= alloc_reg();
				flush_cache();
				sprint(n_str, "%d", n);
				"set	$n_str, $a";
				"sub	$reg_sp, $a, $reg_sp";
			"1:";
				"deccc	4, $a";
				"bnz	1b";
				"st	%g0, [$reg_sp+$a]";	/* HACK delay */
				"andn	$b, 31, $c";
				"and	$b, 31, $b";
				"srl	$c, 3, $c";
				"set	1, $a";
				"sll	$a, $b, $d";
				"st	$d, [$reg_sp+$c]";
				free_reg(a);
				free_reg(b);
				free_reg(c);
				free_reg(d);
			}
		} else {
			a= pop_reg();
			b= pop_reg();
			flush_cache();
			c= alloc_reg();
			d= alloc_reg();
			"sub	$reg_sp, $a, $reg_sp";
		"1:";
			"deccc	4, $a";
			"bnz	1b";
			"st	%g0, [$reg_sp+$a]";	/* HACK delay */
			"andn	$b, 31, $c";
			"and	$b, 31, $b";
			"srl	$c, 3, $c";
			"set	1, $a";
			"sll	$a, $b, $d";
			"st	$d, [$reg_sp+$c]";
			free_reg(a);
			free_reg(b);
			free_reg(c);
			free_reg(d);
		}
	}.


/******************************************************************************/
/*									      */
/*		Group 11 : Array 	 				      */
/*									      */
/******************************************************************************/

C_lar
	($1 == 4) ==>
			Comment(lar, $1);
			force_alloc_output();
			pop_reg_as(reg_o0);
			pop_reg_as(reg_o1);
			pop_reg_as(reg_o2);
			flush_cache();
			"call lar";
			"nop";
			free_output().
	default ==>
			arg_error ("arg error lar", $1).

narg4(lar)

C_sar
	($1 == 4) ==>
			Comment( sar , $1 );
			force_alloc_output();
			pop_reg_as(reg_o0);
			pop_reg_as(reg_o1);
			pop_reg_as(reg_o2);
			flush_cache();
			"call	sar";
			"nop"
			free_output().
	default ==>
			arg_error ("arg error sar", $1).

narg4(sar)

C_aar
	($1 == 4) ==>
			Comment(aar, $1);
			force_alloc_output();
			pop_reg_as(reg_o0);
			pop_reg_as(reg_o1);
			pop_reg_as(reg_o2);
			flush_cache();
			"call	aar";
			"nop";
			soft_alloc_reg(reg_o0);
			free_output();
			push_reg(reg_o0).
	default ==>
			arg_error ("arg error aar", $1).

narg4(aar)

/******************************************************************************/
/*									      */
/*		Group 12 : Compare 	 				      */
/*									      */
/******************************************************************************/

C_cmi
	$1 == 4		==>
	{
		reg_t a;
		reg_t b;
		reg_t c;
		const_str_t d;

		Comment( cmi, $1 );

		if (type_of_tos() == T_cst && const13(top_const()))
		{
			pop_const(d);
			a= pop_reg();
			b= alloc_reg();
			"cmp	$a, $d";
			"be,a	1f";
			"mov	0, $b"; /* delay slot */
			"bg,a	1f";
			"mov	1, $b"; /* delay slot */
			"mov	-1, $b";
		"1:";
			free_reg(a);
			push_reg(b);
		}
		else
		{
			a= pop_reg();
			b= NULL;
			c= alloc_reg();
			if (type_of_tos() == T_cst)
			{
				pop_const(d);
				"cmp	$a, $d";
			}
			else
			{
				b= pop_reg();
				"cmp	$a, $b";
			}
			"be,a	1f";
			"mov	0, $c"; /* delay slot */
			"bg,a	1f";
			"mov	-1, $c"; /* delay slot */
			"mov	1, $c";
		"1:";
			free_reg(a);
			if (b)
				free_reg(b);
			push_reg(c);
		}
	}.
	default		==>
		arg_error ("unimp cmi", $1).

narg4(cmi)

C_cmu	==>
		Comment( cmu, $1 );
		push_const($1);
		C_cmu_narg().

C_cmu_narg	==>
	{
		int n;
		reg_t a;
		reg_t b;
		reg_t c;
		const_str_t d;

		Comment0( cmu_narg );
		if (type_of_tos() == T_cst)
		{
			n= pop_const(NULL);
			if (n != EM_WSIZE)
				arg_error ("unimp cmu", n);
			else
			{
				if (type_of_tos() == T_cst &&
					const13(top_const()))
				{
					pop_const(d);
					a= pop_reg();
					b= alloc_reg();
					"cmp	$a, $d";
					"be,a	1f";
					"mov	0, $b"; /* delay slot */
					"bgu,a	1f";
					"mov	1, $b"; /* delay slot */
					"mov	-1, $b";
				"1:";
					free_reg(a);
					push_reg(b);
				}
				else
				{
					a= pop_reg();
					b= NULL;
					c= alloc_reg();
					if (type_of_tos() == T_cst &&
						const13(top_const()))
					{
						pop_const(d);
						"cmp	$a, $d";
					}
					else
					{
						b= pop_reg();
						"cmp	$a, $b";
					}
					"be,a	1f";
					"mov	0, $c"; /* delay slot */
					"bgu,a	1f";
					"mov	-1, $c"; /* delay slot */
					"mov	1, $c";
				"1:";
					free_reg(a);
					if (b)
						free_reg(b);
					push_reg(c);
				}
			}
		}
		else
			not_implemented ("cmu_narg");
	}.

C_cms	==>
		Comment( cms, $1 );
		push_const($1);
		C_cms_narg().

C_cms_narg	==>
	{
		int n;
		reg_t a;
		reg_t b;
		reg_t c;
		reg_t d;
		reg_t e;
		const_str_t b_str;
		const_str_t n_str;

		Comment0( cms_narg );
		if (type_of_tos() == T_cst && top_const() <= EM_WSIZE)
		{
			n= pop_const(n_str);
			if (n == EM_WSIZE)
			{
				b= NULL;
				c= alloc_reg();
				if (type_of_tos() == T_cst &&
				    const13(top_const()))
				{
					pop_const(b_str);
					a= pop_reg();
					"cmp	$a, $b_str";
				}
				else
				{
					a= pop_reg();
					b= pop_reg();
					"cmp	$a, $b";
				}
				"be,a	1f";
				"mov	0, $c";
				"mov	1, $c";
			"1:";
				free_reg(a);
				if (b)
					free_reg(b);
				push_reg(c);
			}
			else if (n % EM_WSIZE)
				arg_error ("unimp cms", n);
		}
		else
		{
			a= pop_reg();
			flush_cache();
			b= alloc_reg();
			c= alloc_reg();
			d= alloc_reg();

			"add	$reg_sp, $a, $b";
			"dec	4, $b";
		"1:";
			"ld	[$b], $c";
			"ld	[$b+$a], $d";
			"cmp	$d, $c";
			"bne,a	2f";
			"mov	1, $b";	/* delay slot */
			"cmp	$b, $reg_sp";
			"bg	1b";
			"dec	4, $b";	/* delay slot */
			"mov	0, $b";
		"2:";
			"add	$reg_sp, $a, $reg_sp";
			"add	$reg_sp, $a, $reg_sp";

			free_reg(a);
			push_reg(b);
			free_reg(c);
			free_reg(d);
		}
	}.

C_cmp		==>
			Comment0( cmp );
			C_cmu( (arith)4).

C_tlt	==>
		Comment0( tlt );
		{
			reg_t a;
			reg_t b;

			a = pop_reg();
			b= alloc_reg();
			"	tst	$a";
			"	bl,a	1f";
			"	mov	1, $b";		/* delay slot */
			"	set	0, $b";
			"1:";
			free_reg(a);
			push_reg(b);
		}.

C_tle	==>
		Comment0( tle );
		{
			reg_t a;
			reg_t b;

			a = pop_reg();
			b= alloc_reg();
			"tst	$a";
			"ble,a	1f";
			"mov	1, $b";		/* delay slot */
			"set	0, $b";
		"1:";
			free_reg(a);
			push_reg(b);
		}.

C_tge	==>
		Comment0( tge );
		{
			reg_t a;
			reg_t b;

			a = pop_reg();
			b = alloc_reg();
			"	tst	$a";
			"	bge,a	1f";
			"	mov	1, $b";		/* delay slot */
			"	set	0, $b";
			"1:";
			free_reg(a);
			push_reg(b);
		}.

C_tgt	==>
		Comment0( tgt );
		{
			reg_t a;
			reg_t b;

			a = pop_reg();
			b = alloc_reg();
			"	tst	$a";
			"	bg,a	1f";
			"	mov	1, $b";		/* delay slot */
			"	set	0, $b";
			"1:";
			free_reg(a);
			push_reg(b);
		}.

C_tne	==>
		Comment0( tne );
		{
			reg_t a;
			reg_t b;

			a = pop_reg();
			b = alloc_reg();
			"	tst	$a";
			"	bne,a	1f";
			"	mov	1, $b";		/* delay slot */
			"	set	0, $b";		/* sup optimal */
			"1:";
			free_reg(a);
			push_reg(b);
		}.

C_teq	==>
		Comment0( teq );
		{
			reg_t a;
			reg_t b;

			a = pop_reg();
			b = alloc_reg();
			"	tst	$a";
			"	be,a	1f";
			"	mov	1, $b";		/* delay slot */
			"	set	0, $b";
			"1:";
			free_reg(a);
			push_reg(b);
		}.
C_cmf		==>
	Comment( cmf, $1);
	push_const($1);
	C_cmf_narg().

C_cmf_narg	==>
	{
		reg_t a;
		reg_t b;
		reg_t c;
		int n;

		Comment0( cmf_narg);
		if (type_of_tos() == T_cst)
		{
			n= pop_const(NULL);
			if (n == EM_FSIZE)
			{
				a= pop_float();
				b= pop_float();
				c= alloc_reg();
				"fcmpes	$b, $a";
				"nop";
				"fbe,a	1f";
				"mov	0, $c";
				"fbl,a	1f";
				"mov	-1, $c";
				"mov	1, $c";
			"1:";
				free_reg(a);
				free_reg(b);
				push_reg(c);
			}
			else if (n == EM_DSIZE)
			{
				a= pop_double(NULL);
				b= pop_double(NULL);
				c= alloc_reg();
				"fcmped	$b, $a";
				"nop";
				"fbe,a	1f";
				"mov	0, $c";
				"fbl,a	1f";
				"mov	-1, $c";
				"mov	1, $c";
			"1:";
				free_double_reg(a);
				free_double_reg(b);
				push_reg(c);
			}
			else
				arg_error ("cmf", n);
		}
		else
			not_implemented ("cmf_narg");
	}.

/******************************************************************************/
/*									      */
/*		Group 13 : Branch 	 				      */
/*									      */
/******************************************************************************/

C_bra		==>
			Comment( bra , $1 );
			{
				char *lbl;

				flush_cache();
				lbl = $1;
				"b	$lbl";
				"nop";		/* delay slot */
			}.

C_bge	==>
		Comment( bge , $1 );
		{
			char *lbl = $1;
			reg_t a;
			reg_t b;
			const_str_t n_str;

			a= NULL;
			if (type_of_tos() == T_cst &&
				const13(top_const()))
				pop_const(n_str);
			else
				a = pop_reg();
			b = pop_reg();
			flush_cache();
			if (a)
				"cmp	$b, $a";
			else
				"cmp	$b, $n_str";
			"bge	$lbl";
			"nop"		/* delay slot */
			free_reg(a);
			free_reg(b);
		}.

C_bne	==>
		Comment( bne , $1 );
		{
			char *lbl = $1;
			reg_t a;
			reg_t b;
			const_str_t n_str;

			a= NULL;
			if (type_of_tos() == T_cst &&
				const13(top_const()))
				pop_const(n_str);
			else
				a = pop_reg();
			b = pop_reg();
			flush_cache();
			if (a)
				"cmp	$b, $a";
			else
				"cmp	$b, $n_str";
			"bne	$lbl";
			"nop"		/* delay slot */
			free_reg(a);
			free_reg(b);
		}.

C_beq	==>
		Comment( beq , $1 );
		{
			char *lbl = $1;
			reg_t a;
			reg_t b;
			const_str_t n_str;

			a= NULL;
			if (type_of_tos() == T_cst &&
				const13(top_const()))
				pop_const(n_str);
			else
				a = pop_reg();
			b = pop_reg();
			flush_cache();
			if (a)
				"cmp	$b, $a";
			else
				"cmp	$b, $n_str";
			"beq	$lbl";
			"nop"		/* delay slot */
			free_reg(a);
			free_reg(b);
		}.

C_ble	==>
		Comment( ble , $1 );
		{
			char *lbl = $1;
			reg_t a;
			reg_t b;
			const_str_t n_str;

			a= NULL;
			if (type_of_tos() == T_cst &&
				const13(top_const()))
				pop_const(n_str);
			else
				a = pop_reg();
			b = pop_reg();
			flush_cache();
			if (a)
				"cmp	$b, $a";
			else
				"cmp	$b, $n_str";
			"ble	$lbl";
			"nop"		/* delay slot */
			free_reg(a);
			free_reg(b);
		}.

C_blt	==>
		Comment( blt , $1 );
		{
			char *lbl = $1;
			reg_t a;
			reg_t b;
			const_str_t n_str;

			a= NULL;
			if (type_of_tos() == T_cst &&
				const13(top_const()))
				pop_const(n_str);
			else
				a = pop_reg();
			b = pop_reg();
			flush_cache();
			if (a)
				"cmp	$b, $a";
			else
				"cmp	$b, $n_str";
			"bl	$lbl";
			"nop"		/* delay slot */
			free_reg(a);
			free_reg(b);
		}.

C_bgt	==>
		Comment( bgt , $1 );
		{
			char *lbl = $1;
			reg_t a;
			reg_t b;
			const_str_t n_str;

			a= NULL;
			if (type_of_tos() == T_cst &&
				const13(top_const()))
				pop_const(n_str);
			else
				a = pop_reg();
			b = pop_reg();
			flush_cache();
			if (a)
				"cmp	$b, $a";
			else
				"cmp	$b, $n_str";
			"bg	$lbl";
			"nop"		/* delay slot */
			free_reg(a);
			free_reg(b);
		}.

C_zlt	==>
		Comment( zlt , $1 );
		{
			char *lbl = $1;
			reg_t a;

			a = pop_reg();
			flush_cache();
			"tst	$a";
			"bl	$lbl";
			"nop";		/* delay slot */
			free_reg(a);
		}
		.

C_zle	==>
		Comment( zle , $1 );
		{
			char *lbl = $1;
			reg_t a;

			a = pop_reg();
			flush_cache();
			"tst	$a";
			"ble	$lbl";
			"nop";		/* delay slot */
			free_reg(a);
		}
		.

C_zeq	==>
		Comment( zeq , $1 );
		{
			char *lbl = $1;
			reg_t a;

			a = pop_reg();
			flush_cache();
			"tst	$a";
			"be	$lbl";
			"nop";		/* delay slot */
			free_reg(a);
		}
		.

C_zne	==>
		Comment( zne , $1 );
		{
			char *lbl = $1;
			reg_t a;

			a = pop_reg();
			flush_cache();
			"tst	$a";
			"bne	$lbl";
			"nop";		/* delay slot */
			free_reg(a);
		}
		.

C_zge	==>
		Comment( zge , $1 );
		{
			char *lbl = $1;
			reg_t a;

			a = pop_reg();
			flush_cache();
			"tst	$a";
			"bge	$lbl";
			"nop";		/* delay slot */
			free_reg(a);
		}
		.

C_zgt	==>
		Comment( zgt , $1 );
		{
			char *lbl = $1;
			reg_t a;

			a = pop_reg();
			flush_cache();
			"tst	$a";
			"bg	$lbl";
			"nop";		/* delay slot */
			free_reg(a);
		}
		.
/******************************************************************************/
/*                                                                            */
/*			Group 14 : Procedure call instructions		      */
/*							 		      */
/******************************************************************************/

C_cai		==>
			Comment0( cai );
			{
				reg_t a;

				a= pop_reg();
				flush_cache();
				"call	$a";
				"nop";		/* delay slot */
				free_reg(a);
			}.

C_cal		==>
			Comment( cal , $1 );
			{
				char *lbl = $1;
				flush_cache();
				"call	$lbl";
				"nop";		/* delay slot */
			}.

C_lfr
	$1 == 4		==>
	{
		Comment( lfr , $1 );
		forced_alloc_reg(RETL_LD);
		push_reg(RETL_LD);
	}.
	$1 == 8		==>
	{
		Comment( lfr , $1 );
		forced_alloc_reg(RETL_LD);
		forced_alloc_reg(RETH_LD);
		push_reg(RETH_LD);
		push_reg(RETL_LD);
	}.
	default		==>
		arg_error( "lfr", $1).

C_ret
	$1 == 0		==>
	{
		Comment( ret , $1 );
		load_float_regs();
		if (debug)
			free_all_reg_vars();
		"restore";
		"retl";
		"add	%sp, $reg_gap, %sp";
		if (debug)
			alloc_all_reg_vars();
	}.
	$1 == 4		==>
	{
		Comment( ret , $1 );
		soft_alloc_reg(RETL_ST);
		pop_reg_as(RETL_ST);
		free_reg(RETL_ST);
		load_float_regs();
		if (debug)
			free_all_reg_vars();
		"restore";
		"retl";
		"add	%sp, $reg_gap, %sp";
		if (debug)
			alloc_all_reg_vars();
	}.
	$1 == 8		==>
	{
		Comment( ret , $1 );
		soft_alloc_reg(RETL_ST);
		soft_alloc_reg(RETH_ST);
		pop_reg_as(RETL_ST);
		pop_reg_as(RETH_ST);
		free_reg(RETL_ST);
		free_reg(RETH_ST);
		load_float_regs();
		if (debug)
			free_all_reg_vars();
		"restore";
		"retl";
		"add	%sp, $reg_gap, %sp";
		if (debug)
			alloc_all_reg_vars();
	}.
	default		==>
				arg_error( "ret", $1).

/******************************************************************************/
/*                                                                            */
/*			Group 15 : Miscellaneous instructions		      */
/*							 		      */
/******************************************************************************/

C_asp		==>
	Comment( asp , $1 );
	push_const($1);
	C_ass(EM_WSIZE).


C_ass
	$1 == 4		==>
	{
		int n;
		const_str_t n_str;
		reg_t a;

		if (type_of_tos() == T_cst)
		{
			n= pop_const(n_str);
			if (n % EM_WSIZE)
				arg_error ("asp", n);
			else
				if (n>=0)
					pop_nop (n/4);
				else
				{
					flush_cache();
					if (const13(n))
						"inc	$n_str, $reg_sp";
					else
					{
						a= alloc_reg();
						"set	$n_str, $a"
						"add	$reg_sp, $a, $reg_sp";
						free_reg(a);
					}
				}
		}
		else
		{
			a= pop_reg();
			flush_cache();
			"add	$reg_sp, $a, $reg_sp";
			free_reg(a);
		}
	}.
	default		==>
				arg_error( "ass", $1).


narg4(ass)

C_blm		==>
	Comment( blm, $1);
	push_const($1);
	C_bls (EM_WSIZE).

C_bls
	$1 == 4	==>
	{
		reg_t a;
		reg_t b;
		reg_t c;
		reg_t d;
		reg_t ao_reg;
		reg_t bo_reg;
		int n;
		int i;
		const_str_t n_str;
		const_str_t ac_str;
		const_str_t bc_str;
		
		Comment( bls , $1 );
		if (type_of_tos() == T_cst)
		{
			n= pop_const(n_str);
			if (n % EM_WSIZE)
				arg_error ("blm", n);
			else if (n <= MAX_UNROLL)
			{
				c= alloc_reg();
				for (i=0; i<n; i += EM_WSIZE)
				{
					if (type_of_tos() & T_reg2) /* dest */
						a= pop_reg_reg (&ao_reg);
					else
					{
						ao_reg= NULL;
						a= pop_reg_c13(ac_str);
					}
					if (type_of_tos() & T_reg2) /* src */
						b= pop_reg_reg (&bo_reg);
					else
					{
						bo_reg= NULL;
						b= pop_reg_c13(bc_str);
					}
					if (bo_reg)
						"ld	[$b+$bo_reg], $c";
					else
						"ld	[$b+$bc_str], $c";
					if (ao_reg)
						"st	$c, [$a+$ao_reg]";
					else
						"st	$c, [$a+$ac_str]";
					if (bo_reg)
					{
						push_reg(b);
						inc_tos_reg(bo_reg);
					}
					else if (bc_str[0] == '-' ||
						isdigit(bc_str[0]))
					{
						push_reg(b);
						inc_tos(atoi(bc_str));
					}
					else
					{
						"add	$b, $bc_str, $c";
						push_reg(c);
						free_reg(b);
						c= alloc_reg();
					}
					inc_tos(4);
					if (ao_reg)
					{
						push_reg(a);
						inc_tos_reg(ao_reg);
					}
					else if (ac_str[0] == '-' ||
						isdigit(ac_str[0]))
					{
						push_reg(a);
						inc_tos(atoi(ac_str));
					}
					else
					{
						"add	$a, $ac_str, $c";
						push_reg(c);
						free_reg(a);
						c= alloc_reg();
					}
					inc_tos(4);
				}
				pop_nop(2);
				free_reg(c);
			}
			else
			{
				a= pop_reg();	/* dest */
				b= pop_reg();	/* src */
				c= alloc_reg();
				d= alloc_reg();
				"set	$n_str, $c";
			"1:";
				"deccc	4, $c";
				"ld	[$b+$c], $d";
				"bnz	1b";
				"st	$d, [$a+$c]";
				free_reg(a);
				free_reg(b);
				free_reg(c);
				free_reg(d);
			}
		}
		else
		{

			c= pop_reg();	/* size */
			a= pop_reg();	/* dest */
			b= pop_reg();	/* src */
			d= alloc_reg();
		"1:";
			"deccc	4, $c";
			"ld	[$b+$c], $d";
			"bnz	1b";
			"st	$d, [$a+$c]";
			free_reg(a);
			free_reg(b);
			free_reg(c);
			free_reg(d);
		}
	}.

	default		==>
				arg_error( "bls", $1).

narg4(bls)

C_csa
	$1 == 4	==>
		Comment( csa , $1 );
		{
			force_alloc_output();
			pop_reg_as(reg_o0);
			pop_reg_as(reg_o1);
			flush_cache();
			free_output();
			"set	csa, $reg_tmp";
			"jmp	$reg_tmp";
			"nop";
		}.
	default	==>
		arg_error( "csa", $1).

narg4(csa)

C_csb
	$1 == 4		==>
			Comment( csb , $1 );
			{
				force_alloc_output();
				pop_reg_as(reg_o0);
				pop_reg_as(reg_o1);
				flush_cache();
				free_output();
				"set	csb, $reg_tmp";
				"jmp	$reg_tmp";
				"nop";
			}.
	default		==>
				arg_error( "csb", $1).

narg4(csb)

C_dch		==>
	{
		reg_t a;
		reg_t b;
		reg_t c;

		Comment0( dch );
		a= pop_reg();		/* some LB */
		b= alloc_reg();
		c= alloc_reg();
		"ta	3";		/* flush register windows */
		"add	$a, 7, $b";
		"andn	$b, 7, $c";	/* and it's %fp */
		"ld	[$c+4], $b";	/* the previous LB */
		free_reg(a);
		push_reg(b);
		free_reg(c);
	}.

C_dup	==>
		Comment( dup, $1);
		push_const($1);
		C_dus(EM_WSIZE).

C_dus
	$1 == 4 ==>
	{
		int n;
		int i;
		const_str_t n_str;
		const_str_t i_str;
		reg_t a;
		reg_t b;
		reg_t c;

		Comment( dus, $1);

		if (type_of_tos() == T_cst && top_const() <= MAX_UNROLL)
		{
			n= pop_const(n_str);
			if (n == 4 || n == 8 || n<=32)
				dup_tos(n/4);
			else if (n<0 || n % 4)
				arg_error ("dup", n);
			else
			{
				flush_cache();
				a= alloc_reg();
				"sub	$reg_sp, $n_str, $reg_sp";
				for (i=0; i<n; i += 4)
				{
					sprint(i_str, "%d", i);
					"ld	[$reg_sp+$i_str+$n_str], $a";
					"st	$a, [$reg_sp+$i_str]";
				}
				free_reg(a);
			}
		}
		else
		{
			a= pop_reg();
			flush_cache();
			b= alloc_reg();
			c= alloc_reg();
			"mov	$a, $b";
		"1:";
			"dec	STACK_CLICK, $reg_sp";
			"ld	[$reg_sp+ $a], $c";
			"deccc	4, $b";
			"bne	1b";
			"st	$c, [$reg_sp+ $a]"; /* delay slot */
			free_reg(a);
			free_reg(b);
			free_reg(c);
		}
	}.
	default		==>
				arg_error( "dus", $1).

narg4(dus)

C_exg		==>
	Comment( exg, $1 );
	push_const($1);
	C_exg_narg().

C_exg_narg	==>
	{
		reg_t a;
		reg_t b;
		reg_t c;
		reg_t d;
		int n;
		int i;
		const_str_t i_str;
		const_str_t in_str;

		Comment0( exg_narg );
		if (type_of_tos() == T_cst && top_const() <= MAX_UNROLL)
		{
			n= pop_const(NULL);
			if (n==4)
			{
					a= pop_reg();
					b= pop_reg();
					push_reg(a);
					push_reg(b);
			}
			else if (n==8)
			{
				a= pop_reg();
				b= pop_reg();
				c= pop_reg();
				d= pop_reg();
				push_reg(b);
				push_reg(a);
				push_reg(d);
				push_reg(c);
			}
			else if (n>0 && !(n % 4))
			{
				a= alloc_reg();
				b= alloc_reg();
				flush_cache();
				for (i=0; i<n; i += 4)
				{
					sprint(i_str, "%d", i);
					sprint(in_str, "%d", i+n);
					"ld	[$reg_sp+$i_str], $a";
					"ld	[$reg_sp+$in_str], $b";
					"st	$b, [$reg_sp+$i_str]";
					"st	$a, [$reg_sp+$in_str]";
				}
				free_reg(a);
				free_reg(b);
			}
			else
				arg_error ("exg", n);
		}
		else
		{
			a= pop_reg();
			flush_cache();
			b= alloc_reg();
			c= alloc_reg();
			d= alloc_reg();
			"add	$reg_sp, $a, $b";
		"1:";
			"dec	4, $b";
			"cmp	$reg_sp, $b";
			"ld	[$b], $c";
			"ld	[$b+$a], $d";
			"st	$d, [$b]";
			"bne	1b";
			"st	$c, [$b+$a]";	/* delay slot */
			free_reg(a);
			free_reg(b);
			free_reg(c);
			free_reg(d);
		}
	}.

C_fil..		==>
			Comment2( fil , $1 , $2);
#ifdef FAST_LIN_LNI_FIL
			{
				char *lbl = $1;
				int n = $2;

				"set	$lbl+$n, $reg_fil"
			}.
#else
			push_ext($1);
			inc_tos($2);
			push_ext("filn");
			push_const(4);
			C_sts(EM_WSIZE).
#endif


C_gto..		==>
	{
		char *ext;
		reg_t a;
		reg_t b;
		reg_t c;
		reg_t d;

		Comment2( gto , $1 , $2 );

		flush_cache();
		a= reg_g1;
		b= reg_g2;
		c= reg_g3;
		d= reg_g5;
		forced_alloc_reg(a);
		forced_alloc_reg(b);
		forced_alloc_reg(c);
		forced_alloc_reg(d);
		ext= $1;
		push_ext(ext);
		inc_tos($2);
		pop_reg_as(a);
		"ld	[$a+8], $b";
		"mov	$reg_o0, $c";
		"mov	$reg_o1, $d";
	"1:";
		"cmp	$b, $reg_lb";
		"bne,a	1b";
		"restore";
		"ld	[$a+4], $reg_sp";
		"ld	[$a], $b";
		"mov	$c, $reg_o0";
		"jmp	$b";
		"mov	$d, $reg_o1";	/* delay slot */
		free_reg(a);
		free_reg(b);
		free_reg(c);
		free_reg(d);
	}.

C_lim		==>
			Comment0( lim  );
			push_ext("trpim");
			C_loi(4).

C_lin		==>
			Comment( lin , $1 );
#ifdef FAST_LIN_LNI_FIL
			{
				const_str_t n_str;
				sprint(n_str, "%d", $1);
				"set	$n_str, $reg_fil";
			}.
#else
			push_const($1);
			push_ext("lino");
			push_const(4);
			C_sts(EM_WSIZE).
#endif

C_lni		==>
#ifdef FAST_LIN_LNI_FIL
			Comment0( lni );
		 	"inc	$reg_fil".
#else
			{
				reg_t a;
				reg_t b;

				Comment0( lni );
				a = alloc_reg();
				b = alloc_reg();
				"sethi	%hi(lino), $a";
				"ld	[$a+%lo(lino)], $b";
				"inc	$b";
				"st	$b, [$a+%lo(lino)]"
				free_reg(a);
				free_reg(b);
			}.
#endif


C_lor
	$1 == 0		==>
				Comment( lor , $1 );
				soft_alloc_reg(reg_lb);
				push_reg(reg_lb).
	$1 == 1		==>
	{
		reg_t a;

		Comment( lor , $1 );
		a= alloc_reg();
		flush_cache();
		"mov	$reg_sp, $a";
		push_reg(a);
	}.
	$1 == 2		==>
				Comment( lor , $1 );
				{
					reg_t a;
					reg_t b;

					a= alloc_reg();
					b= alloc_reg();
					"set	reghp, $a";
					"ld	[$a], $b";
					push_reg(b);
					free_reg(a);
				}.

	default		==>
				arg_error( "lor", $1).


C_lpb		==>
			Comment0( lpb );
			C_adp( (arith)EM_BSIZE).


C_mon		==>
			Comment0( mon );
			force_alloc_output();
			pop_reg_as(reg_o0);
			"call mon";
			"nop";
			free_output().

C_nop	==>
			Comment0( nop );
			flush_cache();
			.


C_rck
	$1 == 4		==>
	{
		reg_t a;
		reg_t b;
		reg_t c;

		Comment( rck , $1 );
		force_alloc_output();
		a= pop_reg();
		b= pop_reg();
		soft_alloc_reg(b);
		push_reg(b);
		c= alloc_reg();
		"ld	[$a], $c";
		"cmp	$b, $c";
		"bl	1f";
		"ld	[$a+4], $c";
		"cmp	$b, $c";
		"ble	2f";
		"nop";
	"1:";
		"set	ERANGE, $reg_o0";
		"call	trp";
		"nop";
	"2:";
		free_reg(a);
		free_reg(b);
		free_reg(c);
		free_output();
	}.
	default		==>
		arg_error( "rck", $1).

narg4(rck)

C_rtt		==>
			Comment0( rtt );
			C_ret( (arith)0).


C_sig		==>
			Comment0( sig );
			{
				reg_t a;
				reg_t b;
				reg_t c;

				a= pop_reg();
				b= alloc_reg();
				c= alloc_reg();
				"set	trppc, $b";
				"ld	[$b], $c";
				"st	$a, [$b]";
				free_reg(a);
				free_reg(b);
				push_reg(c);
			}.


C_sim		==>
			Comment0( sim );
			{
				reg_t a;
				reg_t b;

				a= pop_reg();
				b= alloc_reg();
				"set	trpim, $b";
				"st	$a, [$b]";
				free_reg(a);
				free_reg(b);
			}.


C_str
	$1 == 0		==>
				Comment( str , $1 );
				flush_cache();
				"ld	[$reg_sp], $reg_lb";
				"add	$reg_lb, 4, %fp";
				"and	%fp, -8, %fp";
				"inc	STACK_CLICK, $reg_sp"
				.
	$1 == 1		==>
	{
		Comment( str , $1 );
		flush_cache();
		"ld [$reg_sp], $reg_sp";
	}.
	$1 == 2		==>
	{
		Comment( str , $1 );
		force_alloc_output();
		pop_reg_as(reg_o0);
		"call	strhp";
		"nop";
		free_output();
	}.
	default		==>
				arg_error( "str", $1).


C_trp		==>
			Comment0( trp );
			force_alloc_output();
			pop_reg_as(reg_o0);
			flush_cache();
			"call	trp";
			"nop";
			free_output().

/*****************************************************************************/

..icon
	$2 == 1  	==>
				Comment( ..icon , $1 );
				gen1( (ONE_BYTE) atoi( $1)).
	$2 == 2  	==>
				Comment( ..icon , $1 );
				gen2( (TWO_BYTES) atoi( $1)).
	$2 == 4  	==>
				Comment( ..icon , $1 );
				gen4( (FOUR_BYTES) atol( $1)).
	default     	==>
				arg_error( "icon", $2).

..ucon
	$2 == 1  	==>
				Comment( ..ucon , $1 );
				gen1( (ONE_BYTE) atoi( $1)).
	$2 == 2  	==>
				Comment( ..ucon , $1 );
				gen2( (TWO_BYTES) atoi( $1)).
	$2 == 4  	==>
				Comment( ..ucon , $1 );
				gen4( (FOUR_BYTES) atol( $1)).
	default     	==>
				arg_error( "icon", $2).

..fcon			==>
				Comment( ..fcon , $1 );
				con_float($1, $2).

/*****************************************************************************/

C_prolog		==>
	Comment0( prolog );
	init_cache();
	"sub	$reg_sp, (EM_BSIZE-4), %g1";
	"and	%g1, -8, %sp";
	"mov	$reg_sp, %g1";
	"save	%sp, $reg_gap, %sp";
	"st	%g0, [%sp+BP_OFFSET]";
	"sub	%g1, EM_BSIZE, $reg_lb";
	init_reg_man();
	forced_alloc_reg(reg_sp);
	forced_alloc_reg(reg_lb);
	forced_alloc_reg(reg_gap);
#ifdef FAST_LIN_LNI_FIL
	reg_lin = alloc_reg();
	reg_fil = alloc_reg();
#endif
	.
C_jump	 		==>
	{
		char *l;

		Comment( jump , $1 );
		l= $1;
		"b	$l";
		"nop";	/* delay slot */
	}.

C_locals		==>
	{
		Comment( locals , $1 );

		soft_alloc_reg(reg_lb);
		push_reg(reg_lb);
		inc_tos(-($1));
		pop_reg_as(reg_sp);
	}.
