/*	$Id: local2.c,v 1.11 2008/11/22 16:12:25 ragge Exp $	*/
/*
 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * Redistributions of source code and documentation must retain the above
 * copyright notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditionsand the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * All advertising materials mentioning features or use of this software
 * must display the following acknowledgement:
 * 	This product includes software developed or owned by Caldera
 *	International, Inc.
 * Neither the name of Caldera International, Inc. nor the names of other
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
 * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 * POSSIBILITY OF SUCH DAMAGE.
 */

# include "pass2.h"
# include "ctype.h"
/* a lot of the machine dependent parts of the second pass */

static void prtype(NODE *n);
static void acon(NODE *p);

/*
 * Print out the prolog assembler.
 * addto and regoff are already calculated.
 */
void
prologue(struct interpass_prolog *ipp)
{
	if (ipp->ipp_vis)
		printf("	.globl %s\n", ipp->ipp_name);
	printf("	.align 4\n");
	printf("%s:\n", ipp->ipp_name);
	printf("	.word 0x%x\n", ipp->ipp_regs[0]);
	if (p2maxautooff)
		printf("	subl2 $%d,%%sp\n", p2maxautooff);
}

/*
 * Called after all instructions in a function are emitted.
 * Generates code for epilog here.
 */
void
eoftn(struct interpass_prolog *ipp)
{
	if (ipp->ipp_ip.ip_lbl == 0)
		return; /* no code needs to be generated */
	printf("	ret\n");
}

struct hoptab { int opmask; char * opstring; } ioptab[] = {

	{ PLUS,	"add", },
	{ MINUS,	"sub", },
	{ MUL,	"mul", },
	{ DIV,	"div", },
	{ OR,	"bis", },
	{ ER,	"xor", },
	{ AND,	"bic", },
	{ -1, ""     },
};

void
hopcode( f, o ){
	/* output the appropriate string from the above table */

	register struct hoptab *q;

	for( q = ioptab;  q->opmask>=0; ++q ){
		if( q->opmask == o ){
			printf( "%s", q->opstring );
/* tbl
			if( f == 'F' ) printf( "e" );
			else if( f == 'D' ) printf( "d" );
   tbl */
/* tbl */
			switch( f ) {
				case 'L':
				case 'W':
				case 'B':
				case 'D':
				case 'F':
					printf("%c", tolower(f));
					break;

				}
/* tbl */
			return;
			}
		}
	cerror( "no hoptab for %s", opst[o] );
	}

char *
rnames[] = {  /* keyed to register number tokens */

	"r0", "r1", "r2", "r3", "r4", "r5",
	"r6", "r7", "r8", "r9", "r10", "r11",
	"ap", "fp", "sp", "pc",
	/* The concatenated regs has the name of the lowest */
	"r0", "r1", "r2", "r3", "r4", "r5",
	"r6", "r7", "r8", "r9", "r10"
	};

int
tlen(p) NODE *p;
{
	switch(p->n_type) {
		case CHAR:
		case UCHAR:
			return(1);

		case SHORT:
		case USHORT:
			return(2);

		case DOUBLE:
		case LDOUBLE:
		case LONGLONG:
		case ULONGLONG:
			return(8);

		default:
			return(4);
		}
}

static int
mixtypes(NODE *p, NODE *q)
{
	TWORD tp, tq;

	tp = p->n_type;
	tq = q->n_type;

	return( (tp==FLOAT || tp==DOUBLE) !=
		(tq==FLOAT || tq==DOUBLE) );
}

void
prtype(NODE *n)
{
	switch (n->n_type)
		{
		case DOUBLE:
			printf("d");
			return;

		case FLOAT:
			printf("f");
			return;

		case LONG:
		case ULONG:
		case INT:
		case UNSIGNED:
			printf("l");
			return;

		case SHORT:
		case USHORT:
			printf("w");
			return;

		case CHAR:
		case UCHAR:
			printf("b");
			return;

		default:
			if ( !ISPTR( n->n_type ) ) cerror("zzzcode- bad type");
			else {
				printf("l");
				return;
				}
		}
}

void
zzzcode( p, c ) register NODE *p; {
	int m;
	int val;
	switch( c ){

	case 'N':  /* logical ops, turned into 0-1 */
		/* use register given by register 1 */
		cbgen( 0, m=getlab2());
		deflab( p->n_label );
		printf( "	clrl	%s\n", rnames[getlr( p, '1' )->n_rval] );
		deflab( m );
		return;

	case 'A':
		{
		register NODE *l, *r;

		if (xdebug) e2print(p, 0, &val, &val);
		r = getlr(p, 'R');
		if (optype(p->n_op) == LTYPE || p->n_op == UMUL) {
			l = resc;
			l->n_type = (r->n_type==FLOAT || r->n_type==DOUBLE ? DOUBLE : INT);
		} else
			l = getlr(p, 'L');
		if (r->n_op == ICON  && r->n_name[0] == '\0') {
			if (r->n_lval == 0) {
				printf("clr");
				prtype(l);
				printf("	");
				adrput(stdout, l);
				return;
			}
			if (r->n_lval < 0 && r->n_lval >= -63) {
				printf("mneg");
				prtype(l);
				r->n_lval = -r->n_lval;
				goto ops;
			}
			r->n_type = (r->n_lval < 0 ?
					(r->n_lval >= -128 ? CHAR
					: (r->n_lval >= -32768 ? SHORT
					: INT )) : r->n_type);
			r->n_type = (r->n_lval >= 0 ?
					(r->n_lval <= 63 ? INT
					: ( r->n_lval <= 127 ? CHAR
					: (r->n_lval <= 255 ? UCHAR
					: (r->n_lval <= 32767 ? SHORT
					: (r->n_lval <= 65535 ? USHORT
					: INT ))))) : r->n_type );
			}
		if (l->n_op == REG && l->n_type != FLOAT && l->n_type != DOUBLE)
			l->n_type = INT;
		if (!mixtypes(l,r))
			{
			if (tlen(l) == tlen(r))
				{
				printf("mov");
				prtype(l);
				goto ops;
				}
			else if (tlen(l) > tlen(r) && ISUNSIGNED(r->n_type))
				{
				printf("movz");
				}
			else
				{
				printf("cvt");
				}
			}
		else
			{
			printf("cvt");
			}
		prtype(r);
		prtype(l);
	ops:
		printf("	");
		adrput(stdout, r);
		printf(",");
		adrput(stdout, l);
		return;
		}

	case 'C':	/* num words pushed on arg stack */
		if (p->n_op == STCALL || p->n_op == USTCALL)
			p->n_qual++;
		printf("$%d", p->n_qual);
		break;

	case 'D':	/* INCR and DECR */
		zzzcode(p->n_left, 'A');
		printf("\n	");

#if 0
	case 'E':	/* INCR and DECR, FOREFF */
		if (p->n_right->n_lval == 1)
			{
			printf("%s", (p->n_op == INCR ? "inc" : "dec") );
			prtype(p->n_left);
			printf("	");
			adrput(stdout, p->n_left);
			return;
			}
		printf("%s", (p->n_op == INCR ? "add" : "sub") );
		prtype(p->n_left);
		printf("2	");
		adrput(stdout, p->n_right);
		printf(",");
		adrput(p->n_left);
		return;
#endif

	case 'F':	/* register type of right operand */
		{
		register NODE *n;
		extern int xdebug;
		register int ty;

		n = getlr( p, 'R' );
		ty = n->n_type;

		if (xdebug) printf("->%d<-", ty);

		if ( ty==DOUBLE) printf("d");
		else if ( ty==FLOAT ) printf("f");
		else printf("l");
		return;
		}

	case 'J': /* jump or ret? */
		{
			extern struct interpass_prolog *epp;
			struct interpass *ip =
			    DLIST_PREV((struct interpass *)epp, qelem);
			if (ip->type != IP_DEFLAB ||
			    ip->ip_lbl != getlr(p, 'L')->n_lval)
				expand(p, FOREFF, "jbr	LL");
			else
				printf("ret");
		}
		break;

	case 'L':	/* type of left operand */
	case 'R':	/* type of right operand */
		{
		register NODE *n;
		extern int xdebug;

		n = getlr ( p, c);
		if (xdebug) printf("->%d<-", n->n_type);

		prtype(n);
		return;
		}

	case 'Z':	/* complement mask for bit instr */
		printf("$%Ld", ~p->n_right->n_lval);
		return;

	case 'U':	/* 32 - n, for unsigned right shifts */
		printf("$" CONFMT, 32 - p->n_right->n_lval );
		return;

	case 'T':	/* rounded structure length for arguments */
		{
		int size;

		size = p->n_stsize;
		SETOFF( size, 4);
		printf("$%d", size);
		return;
		}

	case 'S':  /* structure assignment */
		{
			register NODE *l, *r;
			register int size;

			l = r = NULL; /* XXX gcc */
			if( p->n_op == STASG ){
				l = p->n_left;
				r = p->n_right;

				}
			else if( p->n_op == STARG ){  /* store an arg into a temporary */
				l = getlr( p, '3' );
				r = p->n_left;
				}
			else cerror( "STASG bad" );

			if( r->n_op == ICON ) r->n_op = NAME;
			else if( r->n_op == REG ) r->n_op = OREG;
			else if( r->n_op != OREG ) cerror( "STASG-r" );

			size = p->n_stsize;

			if( size <= 0 || size > 65535 )
				cerror("structure size <0=0 or >65535");

			switch(size) {
				case 1:
					printf("	movb	");
					break;
				case 2:
					printf("	movw	");
					break;
				case 4:
					printf("	movl	");
					break;
				case 8:
					printf("	movq	");
					break;
				default:
					printf("	movc3	$%d,", size);
					break;
			}
			adrput(stdout, r);
			printf(",");
			adrput(stdout, l);
			printf("\n");

			if( r->n_op == NAME ) r->n_op = ICON;
			else if( r->n_op == OREG ) r->n_op = REG;

			}
		break;

	default:
		comperr("illegal zzzcode '%c'", c);
		}
	}

void
rmove( int rt,int  rs, TWORD t ){
	printf( "	%s	%s,%s\n",
		(t==FLOAT ? "movf" : (t==DOUBLE ? "movd" : "movl")),
		rnames[rs], rnames[rt] );
	}

#if 0
setregs(){ /* set up temporary registers */
	fregs = 6;	/* tbl- 6 free regs on VAX (0-5) */
	;
	}

szty(t){ /* size, in registers, needed to hold thing of type t */
	return( (t==DOUBLE||t==FLOAT) ? 2 : 1 );
	}
#endif

int
rewfld( p ) NODE *p; {
	return(1);
	}

#if 0
callreg(p) NODE *p; {
	return( R0 );
	}

base( p ) register NODE *p; {
	register int o = p->op;

	if( (o==ICON && p->name[0] != '\0')) return( 100 ); /* ie no base reg */
	if( o==REG ) return( p->rval );
    if( (o==PLUS || o==MINUS) && p->left->op == REG && p->right->op==ICON)
		return( p->left->rval );
    if( o==OREG && !R2TEST(p->rval) && (p->type==INT || p->type==UNSIGNED || ISPTR(p->type)) )
		return( p->rval + 0200*1 );
	if( o==INCR && p->left->op==REG ) return( p->left->rval + 0200*2 );
	if( o==ASG MINUS && p->left->op==REG) return( p->left->rval + 0200*4 );
	if( o==UNARY MUL && p->left->op==INCR && p->left->left->op==REG
	  && (p->type==INT || p->type==UNSIGNED || ISPTR(p->type)) )
		return( p->left->left->rval + 0200*(1+2) );
	return( -1 );
	}

offset( p, tyl ) register NODE *p; int tyl; {

	if( tyl==1 && p->op==REG && (p->type==INT || p->type==UNSIGNED) ) return( p->rval );
	if( (p->op==LS && p->left->op==REG && (p->left->type==INT || p->left->type==UNSIGNED) &&
	      (p->right->op==ICON && p->right->name[0]=='\0')
	      && (1<<p->right->lval)==tyl))
		return( p->left->rval );
	return( -1 );
	}
#endif

#if 0
void
makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
	register NODE *t;
	NODE *f;

	p->n_op = OREG;
	f = p->n_left; 	/* have to free this subtree later */

	/* init base */
	switch (q->n_op) {
		case ICON:
		case REG:
		case OREG:
			t = q;
			break;

		case MINUS:
			q->n_right->n_lval = -q->n_right->n_lval;
		case PLUS:
			t = q->n_right;
			break;

		case UMUL:
			t = q->n_left->n_left;
			break;

		default:
			cerror("illegal makeor2");
			t = NULL; /* XXX gcc */
	}

	p->n_lval = t->n_lval;
	p->n_name = t->n_name;

	/* init offset */
	p->n_rval = R2PACK( (b & 0177), o, (b>>7) );

	tfree(f);
	return;
	}

int
canaddr( p ) NODE *p; {
	register int o = p->n_op;

	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UMUL && shumul(p->n_left, STARNM|SOREG)) ) return(1);
	return(0);
	}

shltype( o, p ) register NODE *p; {
	return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UMUL && shumul(p->n_left, STARNM|SOREG)) );
	}
#endif

int
fldexpand(NODE *p, int cookie, char **cp)
{
	return 0;
}

int
flshape( p ) register NODE *p; {
	return( p->n_op == REG || p->n_op == NAME || p->n_op == ICON ||
		(p->n_op == OREG && (!R2TEST(p->n_rval) || tlen(p) == 1)) );
	}

int
shtemp( p ) register NODE *p; {
	if( p->n_op == STARG ) p = p->n_left;
	return( p->n_op==NAME || p->n_op ==ICON || p->n_op == OREG || (p->n_op==UMUL && shumul(p->n_left, STARNM|SOREG)) );
	}

int
shumul( p, shape ) register NODE *p; int shape; {
	register int o;
	extern int xdebug;

	if (xdebug) {
		 printf("\nshumul:op=%d,lop=%d,rop=%d", p->n_op, p->n_left->n_op, p->n_right->n_op);
		printf(" prname=%s,plty=%d, prlval=%lld\n", p->n_right->n_name, p->n_left->n_type, p->n_right->n_lval);
		}


	o = p->n_op;
	if( o == NAME || (o == OREG && !R2TEST(p->n_rval)) || o == ICON )
		if (shape & STARNM)
			return SRDIR;

#ifdef notyet
	if( ( o == INCR || o == ASG MINUS ) &&
	    ( p->n_left->n_op == REG && p->n_right->n_op == ICON ) &&
	    p->n_right->n_name[0] == '\0' )
		{
		switch (p->n_left->n_type)
			{
			case CHAR|PTR:
			case UCHAR|PTR:
				o = 1;
				break;

			case SHORT|PTR:
			case USHORT|PTR:
				o = 2;
				break;

			case INT|PTR:
			case UNSIGNED|PTR:
			case LONG|PTR:
			case ULONG|PTR:
			case FLOAT|PTR:
				o = 4;
				break;

			case DOUBLE|PTR:
				o = 8;
				break;

			default:
				if ( ISPTR(p->n_left->n_type) ) {
					o = 4;
					break;
					}
				else return(0);
			}
		return( p->n_right->n_lval == o ? STARREG : 0);
		}
#endif

	return( SRNOPE );
	}

void
adrcon( val ) CONSZ val; {
	printf( "$" );
	printf( CONFMT, val );
	}

void
conput(FILE *fp, NODE *p)
{
	switch( p->n_op ){

	case ICON:
		acon( p );
		return;

	case REG:
		printf( "%s", rnames[p->n_rval] );
		return;

	default:
		cerror( "illegal conput" );
		}
	}

void
insput( p ) register NODE *p; {
	cerror( "insput" );
	}

void
upput( p , size) register NODE *p; {
	cerror( "upput" );
	}

void
adrput(FILE *fp, NODE *p)
{
	register int r;
	/* output an address, with offsets, from p */

	if( p->n_op == FLD ){
		p = p->n_left;
		}
	switch( p->n_op ){

	case NAME:
		acon( p );
		return;

	case ICON:
		/* addressable value of the constant */
		if (p->n_name[0] == '\0') /* uses xxxab */
			printf("$");
		acon(p);
		return;

	case REG:
		printf( "%s", rnames[p->n_rval] );
		return;

	case OREG:
		r = p->n_rval;
		if( R2TEST(r) ){ /* double indexing */
			register int flags;

			flags = R2UPK3(r);
			if( flags & 1 ) printf("*");
			if( flags & 4 ) printf("-");
			if( p->n_lval != 0 || p->n_name[0] != '\0' ) acon(p);
			if( R2UPK1(r) != 100) printf( "(%s)", rnames[R2UPK1(r)] );
			if( flags & 2 ) printf("+");
			printf( "[%s]", rnames[R2UPK2(r)] );
			return;
			}
		if( r == AP ){  /* in the argument region */
			if( p->n_lval <= 0 || p->n_name[0] != '\0' ) werror( "bad arg temp" );
			printf( CONFMT, p->n_lval );
			printf( "(ap)" );
			return;
			}
		if( p->n_lval != 0 || p->n_name[0] != '\0') acon( p );
		printf( "(%s)", rnames[p->n_rval] );
		return;

	case UMUL:
		/* STARNM or STARREG found */
		if( tshape(p, STARNM) ) {
			printf( "*" );
			adrput(0,  p->n_left);
			}
		else {	/* STARREG - really auto inc or dec */
			register NODE *q;

/* tbl
			p = p->n_left;
			p->n_left->n_op = OREG;
			if( p->n_op == INCR ) {
				adrput( p->n_left );
				printf( "+" );
				}
			else {
				printf( "-" );
				adrput( p->n_left );
				}
   tbl */
#ifdef notyet
			printf("%c(%s)%c", (p->n_left->n_op==INCR ? '\0' : '-'),
				rnames[p->n_left->n_left->n_rval], 
				(p->n_left->n_op==INCR ? '+' : '\0') );
#else
			printf("%c(%s)%c", '-',
				rnames[p->n_left->n_left->n_rval], 
				'\0' );
#endif
			p->n_op = OREG;
			p->n_rval = p->n_left->n_left->n_rval;
			q = p->n_left;
#ifdef notyet

			p->n_lval = (p->n_left->n_op == INCR ? -p->n_left->n_right->n_lval : 0);
#else
			p->n_lval = 0;
#endif
			p->n_name[0] = '\0';
			tfree(q);
		}
		return;

	default:
		cerror( "illegal address" );
		return;
	}

}

/*
 * print out a constant
 */
void
acon(NODE *p)
{

	if (p->n_name[0] == '\0') {
		printf(CONFMT, p->n_lval);
	} else if( p->n_lval == 0 ) {
		printf("%s", p->n_name);
	} else {
		printf("%s+", p->n_name);
		printf(CONFMT, p->n_lval);
	}
}

#if 0
genscall( p, cookie ) register NODE *p; {
	/* structure valued call */
	return( gencall( p, cookie ) );
	}

/* tbl */
int gc_numbytes;
/* tbl */

gencall( p, cookie ) register NODE *p; {
	/* generate the call given by p */
	register NODE *p1, *ptemp;
	register temp, temp1;
	register m;

	if( p->right ) temp = argsize( p->right );
	else temp = 0;

	if( p->op == STCALL || p->op == UNARY STCALL ){
		/* set aside room for structure return */

		if( p->stsize > temp ) temp1 = p->stsize;
		else temp1 = temp;
		}

	if( temp > maxargs ) maxargs = temp;
	SETOFF(temp1,4);

	if( p->right ){ /* make temp node, put offset in, and generate args */
		ptemp = talloc();
		ptemp->op = OREG;
		ptemp->lval = -1;
		ptemp->rval = SP;
		ptemp->name[0] = '\0';
		ptemp->rall = NOPREF;
		ptemp->su = 0;
		genargs( p->right, ptemp );
		nfree(ptemp);
		}

	p1 = p->left;
	if( p1->op != ICON ){
		if( p1->op != REG ){
			if( p1->op != OREG || R2TEST(p1->rval) ){
				if( p1->op != NAME ){
					order( p1, INAREG );
					}
				}
			}
		}

/*
	if( p1->op == REG && p->rval == R5 ){
		cerror( "call register overwrite" );
		}
 */
/* tbl
	setup gc_numbytes so reference to ZC works */

	gc_numbytes = temp;
/* tbl */

	p->op = UNARY CALL;
	m = match( p, INTAREG|INTBREG );
/* tbl
	switch( temp ) {
	case 0:
		break;
	case 2:
		printf( "	tst	(sp)+\n" );
		break;
	case 4:
		printf( "	cmp	(sp)+,(sp)+\n" );
		break;
	default:
		printf( "	add	$%d,sp\n", temp);
		}
   tbl */
	return(m != MDONE);
	}
#endif

static char *
ccbranches[] = {
	"jeql",
	"jneq",
	"jleq",
	"jlss",
	"jgeq",
	"jgtr",
	"jlequ",
	"jlssu",
	"jgequ",
	"jgtru",
};

/*
 * printf conditional and unconditional branches
 */
void
cbgen(int o, int lab)
{

	if (o == 0) {
		printf("	jbr     " LABFMT "\n", lab);
	} else {
		if (o > UGT)
			comperr("bad conditional branch: %s", opst[o]);
		printf("\t%s\t" LABFMT "\n", ccbranches[o-EQ], lab);
	}
}

static void
optim2(NODE *p, void *arg)
{
	/* do local tree transformations and optimizations */

	register NODE *r;

	switch( p->n_op ) {

	case AND:
		/* commute L and R to eliminate compliments and constants */
		if( (p->n_left->n_op==ICON&&p->n_left->n_name[0]==0) || p->n_left->n_op==COMPL ) {
			r = p->n_left;
			p->n_left = p->n_right;
			p->n_right = r;
			}
#if 0
	case ASG AND:
		/* change meaning of AND to ~R&L - bic on pdp11 */
		r = p->n_right;
		if( r->op==ICON && r->name[0]==0 ) { /* compliment constant */
			r->lval = ~r->lval;
			}
		else if( r->op==COMPL ) { /* ~~A => A */
			r->op = FREE;
			p->right = r->left;
			}
		else { /* insert complement node */
			p->right = talloc();
			p->right->op = COMPL;
			p->right->rall = NOPREF;
			p->right->type = r->type;
			p->right->left = r;
			p->right->right = NULL;
			}
		break;
#endif
		}
	}

void
myreader(struct interpass *ipole)
{
	struct interpass *ip;

	DLIST_FOREACH(ip, ipole, qelem) {
		if (ip->type != IP_NODE)
			continue;
		walkf(ip->ip_node, optim2, 0);
	}
}

void
mycanon(NODE *p)
{
}

void
myoptim(struct interpass *ip)
{
}

/*
 * Return argument size in regs.
 */
static int
argsiz(NODE *p)
{
	TWORD t = p->n_type;

	if (t == STRTY || t == UNIONTY)
		return p->n_stsize/(SZINT/SZCHAR);
	return szty(t);
}

/*
 * Last chance to do something before calling a function.
 */
void
lastcall(NODE *p)
{
	NODE *op = p;
	int size = 0;

	/* Calculate argument sizes */
	p->n_qual = 0;
	if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
		return;
	for (p = p->n_right; p->n_op == CM; p = p->n_left)
		size += argsiz(p->n_right);
	size += argsiz(p);
	op->n_qual = size; /* XXX */
}

/*
 * Return a class suitable for a specific type.
 */
int
gclass(TWORD t)
{
	return (szty(t) == 2 ? CLASSB : CLASSA);
}

/*
 * For class c, find worst-case displacement of the number of
 * registers in the array r[] indexed by class.
 */
int
COLORMAP(int c, int *r)
{
	int num;

	switch (c) {
	case CLASSA:
		/* there are 12 classa, so min 6 classb are needed to block */
		num = r[CLASSB] * 2;
		num += r[CLASSA];
		return num < 12;
	case CLASSB:
		/* 6 classa may block all classb */
		num = r[CLASSB] + r[CLASSA];
		return num < 6;
	}
	comperr("COLORMAP");
	return 0; /* XXX gcc */
}

/*
 * Special shapes.
 */
int
special(NODE *p, int shape)
{
	return SRNOPE;
}

/*
 * Target-dependent command-line options.
 */
void
mflags(char *str)
{
}
/*
 * Do something target-dependent for xasm arguments.
 * Supposed to find target-specific constraints and rewrite them.
 */
int
myxasm(struct interpass *ip, NODE *p)
{
	return 0;
}
