/*	$Id$	*/

#include "pass2.h"

# define ANYSIGNED TINT|TLONG|TCHAR
# define ANYUSIGNED TUNSIGNED|TULONG|TUCHAR
# define ANYFIXED ANYSIGNED|ANYUSIGNED
# define TL TLONG|TULONG
# define TWORD TUNSIGNED|TINT
# define TCH TCHAR|TUCHAR

struct optab table[] = {
/* First entry must be an empty entry */
{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },

/* (signed) char -> int/pointer */
{ SCONV,	INAREG,
	SCREG,		TCHAR,
	SANY,		TINT|TPOINT,
		NAREG,	RESC1,
		"	mov.b AL, A1\n\texts.b A1\n", },

/* (unsigned) char -> int/pointer */
{ SCONV,	INAREG,
	SCREG,		TUCHAR,
	SANY,		TINT|TPOINT,
		NAREG,	RESC1,
		"	mov.b AL, A1\n", },
    
/* unsigned char -> long */
{ SCONV,	INAREG,
	SCREG,		TUCHAR,
	SANY,		TL,
		NAREG|NASL,	RESC1,
		"	mov.b AL, A1\n	mov.w #0,U1\n", },

/* int or pointer -> (unsigned) long */
{ SCONV,	INAREG,
	SAREG|SNAME,	TWORD|TPOINT,
	SANY,			TL,
		NAREG|NASL,	RESC1,
		"	mov.w AL,A1\n	mov.w #0,U1\n", },

/* char -> (signed) long */
{ SCONV,	INAREG,
	SAREG|SNAME,	TCHAR,
	SANY,			TLONG,
		NAREG|NASL,	RESC1,
		"	exts.b AL\n	exts.w AL\n", },

/* long -> ulong */
{ SCONV,	INAREG,
	SAREG,		TL,
	SANY,			TL,
		0,	RLEFT,
	"", },

/* long -> int or pointer */
{ SCONV,	INAREG,
	SAREG|SOREG|SNAME,	TL,
	SANY,			TWORD|TPOINT,
		NAREG|NASL,	RESC1,
		"	mov.w AL,A1\n", },

/* int -> char */
{ SCONV,	INCREG,
	SAREG,		TWORD,
	SANY,		TCH,
		NCREG,	RESC1,
		"	mov.b AL, A1\n", },

/* int -> long */
{ SCONV,	INAREG,
	SAREG,		TWORD,
	SANY,		TLONG,
		NAREG|NASL,	RESC1,
		"	exts.w AL", },

/* long -> char */
{ SCONV,	INAREG,
	SAREG,		TL,
	SANY,		TCH,
		NAREG|NASL,     RESC1,
		"", },

{ SCONV,	INAREG,
	SAREG,		TPOINT,
	SANY,		TWORD,
		0,	RLEFT,
		"", },

{ PLUS,	INAREG|FOREFF,
	SAREG,	TL,
	SCON|SNAME|SOREG,	TL,
		0,	RLEFT,
		"	add.w AR,AL\n	adc.w UR,UL\n", },

{ MINUS,	INAREG|FOREFF,
	SAREG,	TL,
	SCON|SNAME|SOREG,	TL,
		0,	RLEFT,
		"	sub.w AR,AL\n	sbb.w UR,UL\n", },

{ AND,		INAREG|FOREFF,
	SAREG,			TL,
	SAREG|SNAME|SOREG,	TL,
		0,	RLEFT,
		"	and.w AR,AL\n	and.w UR,UL\n", },

{ ER,		INAREG|FOREFF,
	SAREG,			TL,
	SAREG|SNAME|SOREG,	TL,
		0,	RLEFT,
		"	xor.w AR,AL\n	xor.w UR,UL\n", },

{ OR,		INAREG|FOREFF,
	SAREG,			TL,
	SAREG|SNAME|SOREG,	TL,
		0,	RLEFT,
		"	xor.w AR,AL\n	xor.w UR,UL\n", },

{ COMPL,	INAREG|FOREFF,
	SAREG,			TL,
	SAREG|SNAME|SOREG,	TL,
		0,	RLEFT,
		"	not.w AR,AL\n	not.w UR,UL\n", },
	
{ OPSIMP,	INAREG|FOREFF,
	SAREG,			TWORD|TPOINT,
	SAREG|SNAME|SOREG|SCON,	TWORD|TPOINT,
		0,	RLEFT,
		"	Ow AR,AL\n", },

/* XXX - Is this rule really correct? Having a SAREG shape seems kind of
   strange. Doesn't work. Gives a areg as A1. */
#if 0	
{ OPSIMP,	INBREG,
	SAREG,			TWORD|TPOINT,
	SAREG|SBREG|SNAME|SOREG|SCON,	TWORD|TPOINT,
		NBREG,	RESC1,
		"	++Ow AR,A1\n", },
#endif
	
{ OPSIMP,	INBREG,
	SBREG,			TWORD|TPOINT,
	SAREG|SBREG|SNAME|SOREG|SCON,	TWORD|TPOINT,
		0,	RLEFT,
		"	Ow AR,AL\n", },
	
{ OPSIMP,	INCREG|FOREFF,
	SCREG,			TCH,
	SCREG|SNAME|SOREG|SCON,	TCH,
		0,	RLEFT,
		"	Ob AR,AL\n", },
	
/* XXX - Do these work? check nspecial in order.c */
/* signed integer division */
{ DIV,		INAREG,
	SAREG,			TINT,
	SAREG|SNAME|SOREG,	TWORD,
	  /*2*NAREG|NASL|*/NSPECIAL,		RLEFT,
		"	div.w AR\n	mov.w r0,AL\n", },
      //		"	xor.w r2\n	div.w AR\n", },


/* signed integer/char division - separate entry for FOREFF */
{ DIV,		FOREFF,
	SAREG,			TINT,
	SAREG|SNAME|SOREG,	TWORD,
		0,		0,
		"", },

#if 0
/* signed char division */
{ DIV,		INCREG,
	SCREG,			TCHAR,
	SCREG|SNAME|SOREG,	TCH,
		2*NCREG|NCSL|NSPECIAL,		RLEFT,
		"	div.b AR\n\tmov.b r0l,AL\n", },
      //		"	xor.w r2\n	div.w AR\n", },
#endif
	
/* signed integer modulus, equal to above */
{ MOD,		INAREG,
	SAREG,			TINT,
	SAREG|SNAME|SOREG,	TWORD,
	  /*2*NAREG|NASL|*/NSPECIAL,		RLEFT,
		"	div.w AR\n\tmov r2,AL\n", },

/* signed integer modulus - separate entry for FOREFF */
{ MOD,		FOREFF,
	SAREG,			TINT,
	SAREG|SNAME|SOREG,	TWORD,
		0,		0,
		"", },

/* signed integer multiplication */
{ MUL,		INAREG,
	SAREG,			TINT,
	SAREG|SNAME|SOREG,	TWORD,
		2*NAREG|NASL|NSPECIAL,		RESC1,
		"	mul.w AL,AR\n", },

{ MUL,		FOREFF,
	SAREG,			TINT,
	SAREG|SNAME|SOREG,	TWORD,
		0,	0,
		"", },

#if 0
{ LS,		INAREG,
	SAREG,	TWORD,
	SCON,		TANY,
		0,	RLEFT,
		"	shl.w AR,AL\n", },
#endif

{ LS,		INAREG,
	SAREG,	TWORD,
	SAREG,	TWORD,
		0,	RLEFT,
		"	push.b r1h\n"
		"	mov.b AR,r1h\n"
		"	shl.w r1h,AL\n"
		"	pop.b r1h\n", },

{ LS,		INAREG,
	SAREG,	TL,
	SAREG,	TWORD,
		0,	RLEFT,
		"	push.b r1h\n"
		"	mov.b AR,r1h\n"
		"	shl.l r1h,ZG\n"
		"	pop.b r1h\n", },

{ RS,		INAREG,
	SAREG,	TWORD,
	SAREG,	TWORD,
		0,	RLEFT,
		"	push.b r1h\n"
		"	mov.b AR,r1h\n"
		"	neg.b r1h\n"
		"	shl.w r1h,AL\n"
		"	pop.b r1h\n", },

{ RS,		INAREG,
	SAREG,	TL,
	SAREG,	TWORD,
		0,	RLEFT,
		"	push.b r1h\n"
		"	mov.b AR,r1h\n"
		"	neg.b r1h\n"
		"	shl.l r1h,ZG\n"
		"	pop.b r1h\n", },

#if 0
{ RS,		INAREG,
	SAREG,	TUNSIGNED,
	SCON,		TANY,
		0,	RLEFT,
		"	shl ZA,AL\n", },

{ RS,		INAREG,
	SAREG,	TINT,
	SCON,		TANY,
		0,	RLEFT,
		"	sha ZA,AL\n", },
#endif

{ OPLOG,	FORCC,
	SAREG|SBREG|SOREG|SNAME,	TL,
	SAREG|SBREG|SOREG|SNAME,	TL,
		0,	0,
		"ZF", },

{ OPLOG,	FORCC,
	SBREG|SOREG,	TWORD|TPOINT,
	SCON,			TWORD|TPOINT,
		0,	RESCC,
		"	cmp.w AR,AL\n", },

{ OPLOG,	FORCC,
	SAREG|SBREG|SOREG|SNAME,	TWORD|TPOINT,
	SAREG|SBREG|SOREG|SNAME,	TWORD|TPOINT,
		0,	RESCC,
		"	cmp.w AR,AL\n", },

{ OPLOG,	FORCC,
	SCREG|SOREG|SNAME,	TCH,
	SCREG|SOREG|SNAME,	TCH,
		0,	RESCC,
		"	cmp.b AR,AL\n", },

{ OPLOG,	FORCC,
	SCREG|SOREG|SNAME,	TCH,
	SCREG|SOREG|SNAME,	TCH,
		0,	RESCC,
		"	cmp.b AR,AL\n", },

{ GOTO,		FOREFF,
	SCON,	TANY,
	SANY,	TANY,
		0,	RNOP,
		"	jmp.w ZC\n", },

{ OPLTYPE,	INAREG,
	SANY,	TANY,
	SCON|SNAME|SOREG|SAREG,	TL|TFTN,
		NAREG,	RESC1,
		"	mov.w AR,A1\n	mov.w UR,U1\n", },

{ OPLTYPE,	INAREG,
	SANY,	TANY,
	SCON|SNAME|SOREG|SAREG|SBREG,	TWORD|TPOINT,
		NAREG,	RESC1,
		"	mov.w AR,A1\n", },	

{ OPLTYPE,	INBREG,
	SANY,	TANY,
	SBREG|SCON|SNAME|SOREG|SAREG,	TWORD|TPOINT,
		NBREG,	RESC1,
		"	mov.w AR,A1\n", },	
    /*
{ OPLTYPE,	INAREG,
	SANY,		TANY,
	SCON|SNAME|SOREG,	TCH,
		NAREG,	RESC1,
		"	mov.b AR, A1\n", },

{ OPLTYPE,	INBREG,
	SANY,			TANY,
	SCON|SNAME|SOREG,	TCHAR|TUCHAR,
		NBREG,	RESC1,
		"	mov.b AR,A1\n", },
    */
    
{ OPLTYPE,	INCREG,
	SANY,			TANY,
	SCON|SNAME|SOREG,	TCHAR|TUCHAR,
		NCREG,	RESC1,
		"	mov.b AR,A1\n", },
    
{ COMPL,	INAREG,
	SAREG,	TWORD,
	SANY,		TANY,
		0,	RLEFT,
		"	not.w AL\n", },

{ COMPL,	INCREG,
	SCREG,	TCH,
	SANY,		TANY,
		0,	RLEFT,
		"	not.b AL\n", },
	
/* Push function address */
{ FUNARG,	FOREFF,
	SCON,	TFTN,
	SANY,	TANY,
		0,	RNULL,
		"ZH", },

{ FUNARG,	FOREFF,
	SOREG,	TFTN,
	SANY,	TANY,
		0,	RNULL,
		"ZI", },

{ FUNARG,	FOREFF,
	SNAME|SAREG,	TL|TFTN,
	SANY,	TANY,
		0,	RNULL,
		"	push.w UL\n	push.w AL\n", },

{ FUNARG,	FOREFF,
	SCON|SAREG|SNAME|SOREG,	TWORD|TPOINT,
	SANY,			TANY,
		0,	RNULL,
		"	push.w AL\n", },

{ FUNARG,	FOREFF,
	SAREG|SNAME|SOREG,	TCHAR|TUCHAR,
	SANY,				TANY,
		0,	RNULL,
		"	push.b AL\n", },

/* Match function pointers first */
#if 0
{ ASSIGN,	FOREFF,
	SFTN,	TWORD|TPOINT,
	SFTN,	TWORD|TPOINT,
		NAREG,	0,
		"ZD", },
#endif

{ ASSIGN,	INAREG,
	SAREG,	TFTN,
	SCON,	TFTN,
		0,	RLEFT,
		"ZD", },
    
{ ASSIGN,	INBREG,
	SBREG,	TFTN,
	SCON,	TFTN,
		0,	RLEFT,
		"ZD", },

{ ASSIGN,	INAREG,
	SAREG,	TFTN,
	SBREG|SAREG|SOREG|SNAME,	TFTN,
		0,	RLEFT,
		"	mov.w AR,AL\n	mov.w UR,UL\n", },

{ ASSIGN,	INBREG,
	SBREG,	TFTN,
	SBREG|SAREG|SOREG|SNAME,	TFTN,
		0,	RLEFT,
		"	mov.w AR,AL\n	mov.w UR,UL\n", },
    
{ ASSIGN,	INAREG,
	SBREG|SAREG|SOREG|SNAME,	TFTN,
	SAREG,	TFTN,
		0,	RRIGHT,
		"	mov.w AR,AL\n	mov.w UR,UL\n", },

{ ASSIGN,	INBREG,
	SBREG|SAREG|SOREG|SNAME,	TFTN,
	SBREG,	TFTN,
		0,	RRIGHT,
		"	mov.w AR,AL\n	mov.w UR,UL\n", },

/* a reg -> a reg */
{ ASSIGN,	FOREFF|INAREG,
	SAREG,	TWORD|TPOINT,
	SAREG,	TWORD|TPOINT,
		0,	RLEFT,
		"	mov.w AR,AL\n", },

{ ASSIGN,	INAREG,
	SBREG|SAREG|SOREG|SNAME,	TL,
	SAREG,	TL,
		0,	RRIGHT,
		"	mov.w AR,AL\n	mov.w UR,UL\n", },

{ ASSIGN,	INBREG,
	SBREG|SAREG|SOREG|SNAME,	TL,
	SBREG,	TL,
		0,	RRIGHT,
		"	mov.w AR,AL\n	mov.w UR,UL\n", },
    
{ ASSIGN,	FOREFF,
	SBREG|SAREG|SOREG|SNAME,	TL,
	SCON|SBREG|SAREG|SOREG|SNAME,	TL,
		0,	0,
		"	mov.w AR,AL\n	mov.w UR,UL\n", },

{ ASSIGN,	INAREG|FOREFF,
	SAREG,	TWORD|TPOINT,
	SCON,	TANY,
		0,	RLEFT,
		"	mov.w AR,AL\n", },

{ ASSIGN,	INBREG|FOREFF,
	SBREG,	TWORD|TPOINT,
	SCON,	TANY,
		0,	RLEFT,
		"	mov.w AR,AL\n", },
    
{ ASSIGN,	FOREFF,
	SNAME|SOREG,	TWORD|TPOINT,
	SCON,		TANY,
		0,	0,
		"	mov.w AR,AL\n", },

/* char, oreg/name -> c reg */
{ ASSIGN,	FOREFF|INCREG,
	SCREG,	TCHAR|TUCHAR,
	SOREG|SNAME|SCON,	TCHAR|TUCHAR,
		0,	RLEFT,
		"	mov.b AR,AL\n", },

/* int, oreg/name -> a reg */
{ ASSIGN,	FOREFF|INAREG,
	SAREG,	TWORD|TPOINT,
	SOREG|SNAME,	TWORD|TPOINT,
		0,	RLEFT,
		"	mov.w AR,AL\n", },

{ ASSIGN,	FOREFF|INBREG,
	SBREG,	TWORD|TPOINT,
	SOREG|SNAME,	TWORD|TPOINT,
		0,	RLEFT,
		"	mov.w AR,AL\n", },
    
{ ASSIGN,	FOREFF|INAREG,
	SOREG|SNAME,	TWORD|TPOINT,
	SAREG,	TWORD|TPOINT,
		0,	RRIGHT,
		"	mov.w AR,AL\n", },

{ ASSIGN,	FOREFF|INBREG,
	SOREG|SNAME,	TWORD|TPOINT,
	SBREG,	TWORD|TPOINT,
		0,	RRIGHT,
		"	mov.w AR,AL\n", },
    
{ ASSIGN,	FOREFF|INCREG,
	SOREG|SNAME,	TCHAR|TUCHAR,
	SCREG,	TCHAR|TUCHAR,
		0,	RRIGHT,
		"	mov.b AR,AL\n", },

{ ASSIGN,       FOREFF|INCREG,
        SCREG,    TCHAR|TUCHAR,
        SCREG,  TCHAR|TUCHAR,
                0,      RRIGHT,
                "	mov.b AR,AL\n", },

{ ASSIGN,       FOREFF|INBREG,
        SBREG,    TWORD|TPOINT,
        SBREG,  TWORD|TPOINT,
                0,      RRIGHT,
                "	mov.w AR,AL\n", },
	
{ UMUL, 	INAREG,
	SBREG,	TPOINT|TWORD,
	SANY,  	TFTN,
		NAREG,	RESC1,
		"	mov.w [AL],A1\n	mov.w 2[AL],U1\n", },

{ UMUL, 	INAREG,
	SBREG,	TPOINT|TWORD,
	SANY,  	TPOINT|TWORD,
		NAREG,	RESC1,
		"	mov.w [AL],A1\n", },

{ UMUL, 	INBREG,
	SBREG,	TPOINT|TWORD,
	SANY,  	TPOINT|TWORD,
		NBREG|NBSL,	RESC1,
		"	mov.w [AL],A1\n", },

{ UMUL,		INAREG,
	SBREG,	TCHAR|TUCHAR|TPTRTO,
	SANY,	TCHAR|TUCHAR,
		NAREG,	RESC1,
    		"	mov.b [AL], A1\n", },
    
{ UCALL,	FOREFF,
	SCON,	TANY,
	SANY,	TANY,
		0,	0,
		"	jsr.w CL\nZB", },
    
{ UCALL,	INAREG,
	SCON,	TANY,
	SANY,	TANY,
		NAREG,	RESC1,
		"	jsr.w CL\nZB", },

{ UCALL,        INAREG,
	SNAME|SOREG,	TANY,
	SANY,		TANY,
		NAREG|NASL,     RESC1,  /* should be 0 */
		"	jsri.a AL\nZB", },

{ UCALL,        FOREFF,
	SNAME|SOREG,	TANY,
	SANY,		TANY,
		0,     0,  
		"	jsri.a AL\nZB", },
    
{ UCALL,        INAREG,
	SBREG,   TANY,
	SANY,   TANY,
		NAREG|NASL,     RESC1,  /* should be 0 */
		"	jsri.a [AL]\nZB", },

{ UCALL,        FOREFF,
	SBREG,   TANY,
	SANY,   TANY,
		0,     0,
		"	jsri.a [AL]\nZB", },

    
{ FREE, FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	"help; I'm in trouble\n" },
};

int tablesize = sizeof(table)/sizeof(table[0]);

