"$Header$"
/*
 * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
 *
 *          This product is part of the Amsterdam Compiler Kit.
 *
 * Permission to use, sell, duplicate or disclose this software must be
 * obtained in writing. Requests for such permissions may be sent to
 *
 *      Dr. Andrew S. Tanenbaum
 *      Wiskundig Seminarium
 *      Vrije Universiteit
 *      Postbox 7161
 *      1007 MC Amsterdam
 *      The Netherlands
 *
 */

#define SL 4
#define SSL "4"

#define REGVARS

/********************************************************
 * Back end tables for Intel 8086			*
 * Author : Ed Keizer					*
 * Added register variables: Ceriel Jacobs
 *							*
 * wordsize = 2 bytes, pointersize = 2 bytes.		*
 *							*
 * Register bp is used as LB, sp is used for SP.	*
 * Some global variables are used:			*
 * - .reghp	: the heap pointer			*
 * - .ignmask	: trap ignore mask			*
 * - .trppc	: address of user defined trap handler	*
 *							*
 * Floating point arithmetic and constants are not	*
 * implemented.
 *							*
 ********************************************************/

/* #define DEEPER	1
/*	When DEEPER is disabled, the table contains some
	heuristics based on the assumption that look-ahead will
	be minimal.
	Example: Addition of constants to registers will no take
	place via ax, but in an address register, in the rules for ads.
	Thereby assuming that the resulting register will be used
	to access memory.
	When DEEPER is enabled these heuristics are disabled
	thereby allowing the code-generator too see for itself
	which code will be shorter.
*/

#define SPEED		1
/* This definition produces a slightly different table,
   producing slightly less efficient code with greater speed
*/

#ifdef SPEED

#define NO	nocoercions :

#else

#define NO

#endif

EM_WSIZE=2
EM_PSIZE=2
EM_BSIZE=SL

SIZEFACTOR=5

REGISTERS:

al	= ("al", 2), REG1, ACC1.
ah	= ("ah", 2), REG1.
bl	= ("bl", 2), REG1.
bh	= ("bh", 2), REG1.
cl	= ("cl", 2), REG1, SHIFT_CREG.
ch	= ("ch", 2), REG1.
dl	= ("dl", 2), REG1.
dh	= ("dh", 2), REG1.
ax	= ("ax", 2, al, ah), REG, GENREG, ACC.
cx	= ("cx", 2, cl, ch), REG, GENREG, CXREG, SHIFT_CREG.
dx	= ("dx", 2, dl, dh), REG, GENREG, DXREG.
bx	= ("bx", 2, bl, bh), REG, GENREG, BREG, BXREG, ADDREG.
#ifdef REGVARS
si	= ("si", 2) regvar, RREG, RADDREG.
di	= ("di", 2) regvar, RREG, RADDREG.
#else
si	= ("si", 2), REG, IREG, SIREG, ADDREG.
di	= ("di", 2), REG, IREG, DIREG, ADDREG.
#endif
bp	= ("bp", 2), BREG.

TOKENS:

/********************************
 * Types on the EM-machine	*
 ********************************/

ANYCON		= { INT val ; } 		2 cost=(2, 1) "%[val]"
ADDR_EXTERN	= { STRING off ; }		2 cost=(2, 1) "%[off]"
EXTERN1 	= { STRING off ; }		2 cost=(2,12) "(%[off])"
EXTERN2 	= { STRING off ; }		2 cost=(2,12) "(%[off])"
ADDR_LOCAL	= { INT ind ; } 		2 cost=(1, 9) "%[ind](bp)"
LOCAL2		= { INT ind, size ; }		2 cost=(1,15) "%[ind](bp)"
LOCAL1		= { INT ind, size ; }		2 cost=(1,15) "%[ind](bp)"


/********************************************************
 * Now mostly addressing modes of target machine	*
 ********************************************************/


/*****************************************
 * 'Half modes' consisting of summations *
 * of constant and or register(s)	 *
 *****************************************/

Xreg_off    = { REGISTER reg; STRING off; } 2 cost=(1, 9) "%[off](%[reg])"
Xbpreg_off  = { REGISTER reg; INT ind; }    2 cost=(1,11) "%[ind](bp)(%[reg])"
Rreg_off    = { REGISTER reg; STRING off; } 2 cost=(1, 9) "%[off](%[reg])"
Rbpreg_off  = { REGISTER reg; INT ind; }    2 cost=(1,11) "%[ind](bp)(%[reg])"

/**************************************************
 * Indirect through registers and the modes above *
 * Token names ending on digits are indirect	  *
 **************************************************/


ind_reg2	= { REGISTER reg; }		2 cost=(0,11) "(%[reg])"
ind_regoff2	= { REGISTER reg; STRING off; } 2 cost=(1,15) "%[off](%[reg])"
ind_bpregoff2	= { REGISTER reg; INT ind; }	2 cost=(1,18)
							  "%[ind](bp)(%[reg])"

ind_reg1	= { REGISTER reg; }		2 cost=(0,11) "(%[reg])"
ind_regoff1	= { REGISTER reg; STRING off; } 2 cost=(1,15) "%[off](%[reg])"
ind_bpregoff1	= { REGISTER reg; INT ind; }	2 cost=(1,18)
							  "%[ind](bp)(%[reg])"

TOKENEXPRESSIONS:

/* SCRATCH REGISTERS */
X_ACC		= ACC*SCRATCH
X_ACC1		= ACC1*SCRATCH
X_REG		= REG*SCRATCH
X_BXREG 	= BXREG*SCRATCH
X_DXREG 	= DXREG*SCRATCH
X_CXREG 	= CXREG*SCRATCH
#ifndef REGVARS
X_SIREG 	= SIREG*SCRATCH
X_DIREG 	= DIREG*SCRATCH
#endif
X_ADDREG	= ADDREG*SCRATCH

#ifdef REGVARS
IREG		= RREG
#endif

/* Mode refering to a word in memory */
memory2 	= EXTERN2 + ind_reg2 + ind_regoff2 + ind_bpregoff2 + LOCAL2

/* Mode refering to a byte in memory */
memory1 	= EXTERN1 + ind_reg1 + ind_regoff1 + ind_bpregoff1 + LOCAL1

/* Modes allowed in instructions */
const		= ANYCON + ADDR_EXTERN
register	= REG
#ifdef REGVARS
		  + RREG
#endif
anyreg		= register + BREG
addreg		= ADDREG 
#ifdef REGVARS
		  + RADDREG
#endif
rm		= anyreg + memory2
rmnoacc		= RREG + BREG + CXREG + memory2
rmorconst	= const + rm
noregvar	= const + REG + BREG + memory2
regorconst	= const + anyreg
#ifdef REGVARS
/* Needed because there is a shortage of ADDREG-registers.
   This is the main penalty for having register variables.
*/
regorconstnoaddr = const + RREG + ACC + CXREG + DXREG
#else
regorconstnoaddr = regorconst
#endif
dest		= register + memory2

rm1		= REG1 + memory1
rmorconst1	= const + rm1
regorconst12	= REG1 + GENREG + const
dest1		= REG1 + memory1

/* Modes used to indicate tokens to be removed from the fakestack */
reg_indexed	= ind_reg2 + ind_regoff2 + ind_reg1 + ind_regoff1
lb_indexed	= ind_bpregoff2 + ind_bpregoff1
indexed 	= reg_indexed + lb_indexed
externals	= EXTERN2 + EXTERN1
locals		= LOCAL2 + LOCAL1
all_locals	= locals + lb_indexed
indirects	= externals + reg_indexed
referals	= indirects + locals

/* Miscellaneous */
reg_off		= Xreg_off + Rreg_off
bpreg_off	= Xbpreg_off + Rbpreg_off
halfindir	= reg_off + bpreg_off + ADDR_LOCAL
a_word		= rmorconst + rm1 + halfindir
no_reg_off	= rmorconst + rm1 + ADDR_LOCAL
#ifdef REGVARS
uses_bx		= ADDREG + Xreg_off + Xbpreg_off
#endif

CODE:

/********************************************************
 * Group 1 : load instructions. 			*
 *							*
 * For most load instructions no code is generated.	*
 * Action : put something on the fake-stack.		*
 ********************************************************/

loc 		| |		| {ANYCON, $1}				| |
ldc		| |		| {ANYCON, highw(1)} {ANYCON, loww(1)}	| |
#ifdef REGVARS
lol inreg($1)==2 | |		| regvar($1)				| |
#endif
lol 		| |		| {LOCAL2, $1, 2}			| |
loe		| |		| {EXTERN2, $1} 			| |
loe loe $1==$2	| | 	allocate(REG={EXTERN2, $1})	| %[a] %[a]	| |
#ifdef REGVARS
lol lol $1==$2 && inreg($1)!=2
		| |	allocate(REG={LOCAL2, $1, 2})| %[a] %[a]	| |
#else
lol lol $1==$2	| |	allocate(REG={LOCAL2, $1, 2})| %[a] %[a]	| |
#endif
#ifdef REGVARS
lil inreg($1)==2 | |		| {ind_reg2, regvar($1)}		| |
#endif
lil		| |	allocate(ADDREG={ind_regoff2, bp, tostring($1)})
				| {ind_reg2, %[a]}			| |
lof		| nocoercions : reg_off |
				| {ind_regoff2, %[1.reg],
					%[1.off]+"+"+tostring($1)}	| |
...		| addreg |	| {ind_regoff2,%[1],tostring($1)} 	| |
...		| nocoercions : bpreg_off  |
			  | {ind_bpregoff2,%[1.reg], %[1.ind]+$1} | |
...		| nocoercions : ADDR_EXTERN|
			    | {EXTERN2,%[1.off]+"+"+tostring($1)} | |
...		| nocoercions : ADDR_LOCAL |
				      | {LOCAL2, %[1.ind] + $1,2} | |
lal		| |		| {ADDR_LOCAL, $1}			| |
lae		| |		| {ADDR_EXTERN, $1}			| |
lpb		| |		|			| adp SL  |
lxl $1==0	| |		| {ADDR_LOCAL, 0}			| |
lxl $1==1	| |		| {LOCAL2 ,SL, 2}			| |
lxl $1==2	| |	allocate(ADDREG={ind_regoff2, bp, SSL})
				| {ind_regoff2,%[a], SSL}		| |
lxl $1>2	| |	allocate(ADDREG={ind_regoff2, bp, SSL},
				 CXREG={ANYCON,$1-1})
			"1:\tmov %[a],4(%[a])"
			"loop 1b"
			samecc erase(%[a]) erase(%[b])
				| %[a]					| |
lxa $1==0	| |		| {ADDR_LOCAL, SL}			| |
lxa $1==1	| |	allocate(ADDREG={ind_regoff2, bp, SSL })
				| {Xreg_off, %[a], SSL } 		| |
lxa $1==2	| |	allocate(ADDREG={ind_regoff2, bp, SSL })
			move({ind_regoff2, %[a], SSL }, %[a])
				| {Xreg_off, %[a], SSL } 		| |
lxa $1 > 2	| |	allocate(ADDREG={ind_regoff2,bp,SSL},
				 CXREG={ANYCON,$1-1})
			"1:\tmov %[a],4(%[a])"
			"loop 1b"
			samecc erase(%[a]) erase(%[b])
				| {Xreg_off, %[a], SSL } 		| |
dch		| |		|			       | loi 2	  |
loi $1==2	| addreg     |	| {ind_reg2, %[1]}			| |
...		| nocoercions : reg_off    |
			    | {ind_regoff2, %[1.reg], %[1.off]} | |
...		| nocoercions : bpreg_off  |
			| {ind_bpregoff2, %[1.reg], %[1.ind]}	| |
...		| nocoercions : ADDR_EXTERN|
			| {EXTERN2, %[1.off]}			| |
...		| nocoercions : ADDR_LOCAL |
			| {LOCAL2, %[1.ind],2}			| |
loi $1==1	| addreg     |	| {ind_reg1, %[1]}			| |
...		| nocoercions : reg_off    |
				| {ind_regoff1, %[1.reg], %[1.off]}	| |
...		| nocoercions : bpreg_off  |
			| {ind_bpregoff1, %[1.reg], %[1.ind]}	| |
...		| nocoercions : ADDR_EXTERN |
			| {EXTERN1, %[1.off]}			| |
...		| nocoercions : ADDR_LOCAL |
			| {LOCAL1, %[1.ind],1}			| |
loi $1==4	| addreg     |	| {ind_regoff2,%[1],"2"} {ind_reg2,%[1]}| |
...		| nocoercions : reg_off    |
				| {ind_regoff2,%[1.reg], %[1.off]+"+2"}
				  {ind_regoff2,%[1.reg], %[1.off]}	| |
...		| nocoercions : bpreg_off  |
			| {ind_bpregoff2, %[1.reg], %[1.ind]+2}
				  {ind_bpregoff2, %[1.reg], %[1.ind]}	| |
...		| nocoercions : ADDR_LOCAL |	|
			      {LOCAL2,%[1.ind]+2,2} {LOCAL2,%[1.ind],2} | |
...		| nocoercions : ADDR_EXTERN|	| {EXTERN2, %[1.off]+"+2"}
				  {EXTERN2, %[1.off]}			| |
/*
loi $1>4	| noregvar |
			remove(ALL)
			allocate(CXREG={ANYCON,$1/2})
			"mov ax,si"
			"mov bx,di"
			"mov si,%[1]"
			"sub sp,%($1%)"
			"mov di,sp"
			"rep movs"
			"mov si,ax"
			"mov di,bx"
			erase(%[a])  | | | (16,16+$1*9)
WRONG! */
loi $1>4	| X_BXREG |
			remove(ALL)
			allocate(CXREG={ANYCON,$1})
			"call .loi"
			erase(%[a]) erase(%[1]) | | | (3,40+$1*9)
los $1==2	| X_CXREG X_BXREG |
			remove(ALL)
			"call .los"
			erase(%[1]) erase(%[2]) 		|	| |
los !defined($1)| rm X_CXREG X_BXREG |
			remove(ALL)
			"cmp %[1],2"
			"jne .unknown"
			"call .los"
			erase(%[2]) erase(%[3]) 		|	| |
ldl		| |		| {LOCAL2, $1+2,2} {LOCAL2, $1,2}	| |
lde		| |		| {EXTERN2, $1+"+2"} {EXTERN2, $1}	| |
ldf		| nocoercions : reg_off |
				| {ind_regoff2, %[1.reg],
					%[1.off]+"+2+"+tostring($1)}
				  {ind_regoff2, %[1.reg],
					%[1.off]+"+"+tostring($1)}	| |
...		| addreg |
				| {ind_regoff2, %[1], tostring($1+2)}
				  {ind_regoff2, %[1], tostring($1)}	| |
...		| nocoercions : bpreg_off |
				| {ind_bpregoff2,%[1.reg], %[1.ind]+2+$1}
				  {ind_bpregoff2,%[1.reg], %[1.ind]+$1} | |
...		| nocoercions : ADDR_EXTERN |
				| {EXTERN2,%[1.off]+"+2+"+tostring($1)}
				  {EXTERN2,%[1.off]+"+"+tostring($1)}	| |
...		| nocoercions : ADDR_LOCAL |
				| {LOCAL2, %[1.ind] + $1 + 2, 2}
				  {LOCAL2, %[1.ind] + $1, 2}		| |
lpi		| |		| {ADDR_EXTERN, $1}			| |
/* This code sequence is generated by the C-compiler to tackle
   char parameters, on the 8086 it reduces to nil */
lol lal sti $1==$2 && $3<=2 | | |					| |

/****************************************************************
 * Group 2 : Store instructions.				*
 *								*
 * These instructions are likely to ruin the fake-stack.	*
 * We don't expect many items on the fake-stack anyway		*
 * because we seem to have evaluated an expression just now.	*
 ****************************************************************/

#ifdef REGVARS
stl inreg($1)==2
		| rmorconst |
			remove(regvar($1))
			move(%[1], regvar($1))			|	| |
...		| nocoercions : STACK |
			remove(regvar($1))
			"pop %(regvar($1)%)" samecc		|  | |(1,8)
#endif
stl		| regorconst |
			remove(indexed)
			remove(locals, %[ind]>=$1 && %[ind]<$1+2 )
			move(%[1],{ind_regoff2,bp,tostring($1)})|	| |
...		| nocoercions : STACK |
			"pop $1(bp)" samecc			|  | |(2,26)
ste		| regorconst |
			remove(indirects)
			move(%[1], {EXTERN2, $1 })		|	| |
...		| nocoercions : STACK | "pop ($1)" samecc	| | |
#ifdef REGVARS
sil inreg($1)==2| regorconst |
			remove(referals)
			move(%[1],{ind_reg2, regvar($1)})			|	| |
...		| nocoercions : STACK |
			"pop (%(regvar($1)%))"	samecc		|  | |(2,26)
#endif
sil		| regorconstnoaddr |
			allocate(ADDREG={ind_regoff2, bp, tostring($1)})
			remove(referals)
			move(%[1], {ind_reg2, %[a]})		|	| |
...		| STACK |
			allocate(ADDREG={ind_regoff2, bp, tostring($1)})
			remove(referals)
			"pop (%[a])"	samecc			| | | (2,26)
stf		| addreg regorconst |
			remove(referals)
			move(%[2],{ind_regoff2,%[1],tostring($1)})|	| |
...		| nocoercions : addreg STACK |
			remove(referals)
			"pop $1(%[1])" samecc			      | | |
...		| reg_off regorconst |
			remove(referals)
			move(%[2],{ind_regoff2,%[1.reg],
				%[1.off]+"+"+tostring($1)})	|	| |
...		| nocoercions : halfindir STACK |
			remove(referals)
			"pop $1+%[1]" samecc			      | | |
...		| nocoercions : ADDR_LOCAL | | 			| stl %[1.ind]+$1 |
...		| bpreg_off regorconst |
			remove(all_locals)
			remove(indexed)
			move(%[2],{ind_bpregoff2,%[1.reg],
					%[1.ind]+$1})		|	| |
/*
...		| ADDR_EXTERN regorconst |
			remove(indirects)
			move(%[2],{EXTERN2,%[1.off]+"+"+tostring($1)})| | |
*/
sti $1==2	| addreg regorconst |
			remove(referals)
			move(%[2],{ind_reg2,%[1]})		|	| |
...		| nocoercions : addreg STACK |
			remove(referals)
			"pop (%[1])" samecc			      | | |
...		| reg_off regorconst |
			remove(referals)
			move(%[2],{ind_regoff2,%[1.reg],%[1.off]})  |	| |
...		| nocoercions : reg_off STACK |
			remove(referals)
			"pop %[1]" samecc			      | | |
...		| nocoercions : ADDR_LOCAL | 		| | stl %[1.ind] |
...		| bpreg_off regorconst |
			remove(all_locals)
			remove(indexed)
			move(%[2],{ind_bpregoff2,%[1.reg], %[1.ind]}) | | |
...		| nocoercions : bpreg_off STACK |
			remove(all_locals)
			remove(indexed)
			"pop %[1]" samecc			      | | |
...		| ADDR_EXTERN regorconst |
			remove(indirects)
			move(%[2],{EXTERN2,%[1.off]})		|	| |
...		| nocoercions : ADDR_EXTERN STACK |
			remove(indirects)
			"pop (%[1])" samecc			      | | |
sti $1==1	| addreg regorconst12 |
			remove(referals)
			move(%[2],{ind_reg1,%[1]})		|	| |
...		| reg_off regorconst12 |
			remove(referals)
			move(%[2],{ind_regoff1,%[1.reg],%[1.off]})  |	| |
...		| bpreg_off regorconst12 |
			remove(all_locals)
			remove(indexed)
			move(%[2],{ind_bpregoff1,%[1.reg], %[1.ind]}) | | |
...		| ADDR_EXTERN regorconst12 |
			remove(indirects)
			move(%[2],{EXTERN1,%[1.off]})		|	| |
...		| ADDR_LOCAL regorconst12 |
			remove(indexed)
			remove(locals,
				%[ind]<=%[1.ind] && %[ind]+%[size]>%[1.ind] )
			move(%[2],{LOCAL1, %[1.ind], 1})
								|	| |
sti $1==4	| addreg regorconst regorconst |
			remove(referals)
			move(%[2],{ind_reg2,%[1]})
			move(%[3],{ind_regoff2,%[1],"2"})	|	| |
...		| reg_off regorconst regorconst |
			remove(referals)
			move(%[2],{ind_regoff2,%[1.reg],%[1.off]})
			move(%[3],{ind_regoff2,%[1.reg],%[1.off]+"+2"})| | |
...		| bpreg_off regorconst regorconst |
			remove(all_locals)
			remove(indexed)
			move(%[2],{ind_bpregoff2,%[1.reg], %[1.ind]})
			move(%[3],{ind_bpregoff2,%[1.reg], %[1.ind]+2})| | |
...		| ADDR_EXTERN regorconst regorconst |
			remove(indirects)
			move(%[2],{EXTERN2,%[1.off]})
			move(%[3],{EXTERN2,%[1.off]+"+2"})	|	| |
...		| ADDR_LOCAL regorconst regorconst |
			remove(indexed)
			remove(locals, %[ind]>=%[1.ind] && %[ind]<%[1.ind]+4 )
			move(%[2],{ind_regoff2, bp, tostring(%[1.ind])})
			move(%[3],{ind_regoff2, bp,
						tostring(%[1.ind]+2)})| | |
/*
sti $1>4	| noregvar |
			remove(ALL)
			allocate(CXREG={ANYCON,$1/2})
			"mov ax,si"
			"mov bx,di"
			"mov si,sp"
			"mov di,%[1]"
			"rep movs"
			"mov sp,si"
			"mov si,ax"
			"mov di,bx"
			erase(%[a]) |	| | (14,12+$1*8)
WRONG! */
sti $1>4	| X_BXREG |
			remove(ALL)
			allocate(CXREG={ANYCON,$1})
			"call .sti"
			erase(%[a]) erase(%[1]) | | | (3,40+$1*9)
/* This sort of construction gives problems in the codegenerator
   because of the potential verly large lookahead
...		| X_ADDREG |
			remove(ALL)
			"pop (%[1])"
			"add %[1],2"
			erase(%[1])		| %[1]	| sti $1-2 | (5,30)
*/
sts $1==2	| X_CXREG X_BXREG |
			remove(ALL)
			"call .sts"
			erase(%[1]) erase(%[2]) 		|	| |
sdl		| regorconst regorconst  |  | %[2] %[1]  | stl $1 stl $1+2 |
...		| nocoercions: STACK |	| | stl $1 stl $1+2 |
sde		| regorconst regorconst  |  | %[2] %[1]  | ste $1 ste $1+"+2" |
...		| nocoercions: STACK |	| | ste $1 ste $1+"+2" |
sdf		| addreg regorconst regorconst |
			remove(referals)
			move(%[2],{ind_regoff2,%[1],tostring($1)})
			move(%[3],{ind_regoff2,%[1],tostring($1+2)})|   | |
...		| nocoercions : addreg STACK |
			remove(referals)
			"pop $1(%[1])"
			"pop %($1+2%)(%[1])" samecc		      | | |
...		| reg_off regorconst regorconst |
			remove(referals)
			move(%[2],{ind_regoff2,%[1.reg],
				%[1.off]+"+"+tostring($1)})
			move(%[3],{ind_regoff2,%[1.reg],
				%[1.off]+"+"+tostring($1+2)})	|	| |
...		| nocoercions : halfindir STACK |
			remove(referals)
			"pop $1+%[1]"
			"pop %($1+2%)+%[1]" samecc		      | | |
	/* Funny things happen when the sign changes in the stl parameters */
...		| nocoercions: ADDR_LOCAL | |      | stl %[1.ind]+$1 stl %[1.ind]+$1+2 |
...		| bpreg_off regorconst regorconst |
			remove(all_locals)
			remove(indexed)
			move(%[2],{ind_bpregoff2,%[1.reg],
					%[1.ind]+$1})
			move(%[3],{ind_bpregoff2,%[1.reg],
					%[1.ind]+$1+2})		|	| |
...		| halfindir regorconst |
			remove(referals)
			"mov %[1],%[2]"
			samecc | %[1] | stf $1+2 | (0,12)+%[1]+%[2]+%[1]

/****************************************************************
 * Group 3 : Integer arithmetic.				*
 *								*
 * Implemented (sometimes with the use of subroutines) :	*
 * all 2 and 4 byte arithmetic. 				*
 ****************************************************************/

adi $1==2	| NO X_REG rmorconst |
			"add %[1],%[2]"
			erase(%[1]) setcc(%[1]) | %[1]	| | (2,3) + %[2]
...		| rmorconst X_REG |
			"add %[2],%[1]"
			erase(%[2]) setcc(%[2]) | %[2]	| | (2,3) + %[1]
...		| X_ACC const |
			"add %[1],%[2]"
			erase(%[1]) setcc(%[1]) | %[1]	| | (3,4)
...		| const X_ACC |
			"add %[2],%[1]"
			erase(%[2]) setcc(%[2]) | %[2]	| | (3,4)
adi $1==4	| NO X_REG X_REG rmorconst rmorconst |
			"add %[1],%[3]"
			"adc %[2],%[4]"
			setcc(%[2]) erase(%[1]) erase(%[2])
						| %[2] %[1] | |(4,6)+%[4]+%[3]
...		| nocoercions: X_ACC X_REG const rmorconst |
			"add %[1],%[3]"
			"adc %[2],%[4]"
			setcc(%[2]) erase(%[1]) erase(%[2])
						| %[2] %[1] | |(5,7)+%[4]
...		| rmorconst rmorconst X_REG X_REG |
			"add %[3],%[1]"
			"adc %[4],%[2]"
			setcc(%[4]) erase(%[3]) erase(%[4])
						| %[4] %[3] | |(4,6)+%[1]+%[2]
...		| nocoercions: const rmorconst X_ACC X_REG |
			"add %[3],%[1]"
			"adc %[4],%[2]"
			setcc(%[4]) erase(%[3]) erase(%[4])
						| %[4] %[3] | |(5,7)+%[2]
adi !defined($1)| X_CXREG X_ACC |
			remove(ALL)
			"call .adi"
			erase(%[1]) erase(%[2])        | ax | |
sbi $1==2	| rmorconst X_REG |
			"sub %[2],%[1]"
			erase(%[2]) setcc(%[2])      | %[2] | | (2,3) + %[1]
...		| const X_ACC |
			"sub %[2],%[1]"
			erase(%[2]) setcc(%[2])      | %[2] | | (3,4)
...		| NO X_REG rmorconst |
			"sub %[1],%[2]"
			"neg %[1]"
			erase(%[1]) setcc(%[1])      | %[1] | | (4,6) + %[2]
...		| NO X_ACC const |
			"sub %[1],%[2]"
			"neg %[1]"
			erase(%[1]) setcc(%[1])      | %[1] | | (5,7)
sbi $1==4	| rmorconst rmorconst X_REG X_REG |
			"sub %[3],%[1]"
			"sbb %[4],%[2]"
			setcc(%[4]) erase(%[3]) erase(%[4])
						| %[4] %[3] | |(4,6)+%[1]+%[2]
...		| nocoercions: const rmorconst-ACC X_ACC X_REG |
			"sub %[3],%[1]"
			"sbb %[4],%[2]"
			setcc(%[4]) erase(%[3]) erase(%[4])
						| %[4] %[3] | |(5,7)+%[2]
sbi !defined($1)| X_CXREG X_ACC |
			remove(ALL)
			"call .sbi"
			erase(%[1]) erase(%[2])        | ax | |
mli $1==2	| X_ACC rm |
			allocate(%[2],DXREG)
			"mul %[2]"
			/* mul and imul have same low order result
			   but mul is faster
			*/
			nocc erase(%[1])	    | %[1]  | |(2,118)+%[2]
...		| rmnoacc rmorconst |
			allocate(%[2],ACC=%[2],DXREG)
			"mul %[1]"
			nocc erase(%[a])	    | ax  | |(2,118)+%[1]
mli $1==4	| X_ACC X_DXREG |
			remove(ALL)
			"call .mli4"
			erase(ax) erase(dx) setcc(dx)    | dx ax | |
/* Not now,
mli !defined($1)| X_ACC |
			remove(ALL)
			"call .mli"		    |	    | |
*/
dvi $1==2	| rmnoacc rmorconst |
			allocate(%[2], ACC=%[2], DXREG)
			"cwd"
			"idiv %[1]"
			erase(%[a])		       | ax | |(3,176)+%[1]
dvi $1==4	| |	remove(ALL)
			"call .dvi4"		    | dx ax | |
/*
dvi !defined($1)| X_ACC |
			remove(ALL)
			"call .dvi" erase(%[1])     |	    | |
*/
rmi $1==2	| rmnoacc rmorconst |
			allocate(%[2], ACC=%[2], DXREG)
			"cwd"
			"idiv %[1]"
			erase(%[a])		       | dx | |(3,176)+%[1]
rmi $1==4	| |	remove(ALL)
			"call .rmi4"		    | dx ax | |
/*
rmi !defined($1)| X_ACC |
			remove(ALL)
			"call .rmi" erase(%[1])     |	    | |
*/
ngi $1==2	| X_REG |
			"neg %[1]"
			setcc(%[1]) erase(%[1])     | %[1]  | |(2,3)
ngi $1==4	| X_REG X_REG |
			"neg %[2]"
			"neg %[1]"
			"sbb %[2],0"
			setcc(%[2]) erase(%[1]) erase(%[2])
						| %[2] %[1] | | (8,10)
/*
ngi !defined($1)| X_ACC |
			remove(ALL)
			"call .ngi"		    |	    | |
*/
loc sli $1==1 && $2==2 | X_REG |
			"sal %[1],1"
			setcc(%[1]) erase(%[1])      | %[1] | | (2,2)
loc sli $1==1 && $2==4 | X_REG X_REG |
			"sal %[1],1"
			"rcl %[2],1"
			erase(%[1]) erase(%[2])	    | %[2] %[1] | |
loc sli $1==16 && $2==4 | rmorconst rmorconst | | %[1] {ANYCON, 0} | |
sli $1==2	| SHIFT_CREG X_REG |
			"sal %[2],cl"
			setcc(%[2]) erase(%[2])     | %[2]  | | (2,8)
sli $1==4	| X_CXREG X_REG X_REG |
			"jcxz 1f"
			"2: sal %[2],1"
			"rcl %[3],1"
			"loop 2b\n1:"
			erase(%[1]) erase(%[2]) erase(%[3])
						| %[3] %[2] | |
/*
sli !defined($1)| X_ACC |
			remove(ALL)
			"call .sli"		    |	    | |
*/
loc sri $1==1 && $2==2 | X_REG |
			"sar %[1],1"
			setcc(%[1]) erase(%[1])      | %[1] | | (2,2)
loc sri $1==1 && $2==4 | X_REG X_REG |
			"sar %[2],1"
			"rcr %[1],1"
			erase(%[1]) erase(%[2])	    | %[2] %[1] | |
sri $1==2	| SHIFT_CREG X_REG |
			"sar %[2],cl"
			setcc(%[2]) erase(%[2])     | %[2]  | | (2,8)
sri $1==4	| X_CXREG X_REG X_REG |
			"jcxz 1f"
			"2: sar %[3],1"
			"rcr %[2],1"
			"loop 2b\n1:"
			erase(%[1]) erase(%[2]) erase(%[3])
						| %[3] %[2] | |
/*
sri !defined($1)| X_ACC |
			remove(ALL)
			"call .sri"		    |	    | |
*/


/************************************************
 * Group 4 : unsigned arithmetic		*
 *						*
 * adu = adi					*
 * sbu = sbi					*
 * slu = sli					*
 * mlu = mli					*
 *						*
 * Supported : 2- and 4 byte arithmetic.	*
 ************************************************/

adu		| |	|				    | adi $1 |
sbu		| |	|				    | sbi $1 |
mlu		| |	|				    | mli $1 |
dvu $1==2	| rmnoacc rmorconst |
			allocate(%[2],ACC=%[2],DXREG={ANYCON,0})
			"div %[1]"
			erase(%[b]) erase(%[a])      | ax | |(2,149)+%[1]
dvu $1==4	| |	remove(ALL)
			"call .dvu4"		    | dx ax | |
/*
dvu !defined($1)| X_ACC |
			remove(ALL)
			"call .dvu" erase(%[1])     |	    | |
*/
rmu $1==2	| rmnoacc rmorconst |
			allocate(%[2],ACC=%[2],DXREG={ANYCON,0})
			"div %[1]"
			erase(%[b]) erase(%[a])        | dx | |(3,149)+%[1]
rmu $1==4	| |	remove(ALL)
			"call .rmu4"		    | dx ax | |
/*
rmu !defined($1)| X_ACC |
			remove(ALL)
			"call .rmu" erase(%[1])     |	    | |
*/
slu		| |	|				    | sli $1 |
loc slu		| |	|				    | loc $1 sli $2 |
lol loc slu	| |	|				    | lol $1 loc $2 sli $3 |
loc sru $1==1 && $2==2 | X_REG |
			"shr %[1],1"
			setcc(%[1]) erase(%[1])      | %[1] | | (2,2)
loc sru $1==16 && $2==4 | rmorconst rmorconst | | {ANYCON, 0} %[2] | |
sru $1==2	| SHIFT_CREG X_REG |
			"shr %[2],cl"
			setcc(%[2]) erase(%[2])      | %[2] | | (2,8)
sru $1==4	| X_CXREG X_REG X_REG |
			"jcxz 1f" /* result => samecc */
			"2: shr %[3],1"
			"rcr %[2],1"
			"loop 2b\n1:"
			erase(%[1]) erase(%[2]) erase(%[3])
						| %[3] %[2] | |
/*
sru !defined($1)| X_ACC |
			remove(ALL)
			"call .sru"		    |	    | |
*/

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

/* Floating point stuff
 * Arithmetic instructions
 */
 
adf $1==4	| | | | cal ".adf4" asp 4 |
adf $1==8	| | | | cal ".adf8" asp 8 |
sbf $1==4	| | | | cal ".sbf4" asp 4 |
sbf $1==8	| | | | cal ".sbf8" asp 8 |
mlf $1==4	| | | | cal ".mlf4" asp 4 |
mlf $1==8	| | | | cal ".mlf8" asp 8 |
dvf $1==4	| | | | cal ".dvf4" asp 4 |
dvf $1==8	| | | | cal ".dvf8" asp 8 |
ngf $1==4	| | | | cal ".ngf4" |
ngf $1==8	| | | | cal ".ngf8" |
fif $1==4	| | | | cal ".fif4" |
fif $1==8	| | | | cal ".fif8" |
fef $1==4	| X_REG X_REG |
		remove(ALL)
		"push %[2]"
		"push %[2]"
		"push %[1]"	| | cal ".fef4" |
fef $1==8	| X_REG X_REG X_REG X_REG |
		remove(ALL)
		"push %[4]"
		"push %[4]"
		"push %[3]"
		"push %[2]"
		"push %[1]"	| | cal ".fef8" |

/****************************************
 * Group 6 : pointer arithmetic.	*
 *					*
 * Pointers have size 2 bytes.		*
 ****************************************/

adp $1==1	| nocoercions : Xreg_off | |
			  {Xreg_off, %[1.reg],%[1.off]+"+"+tostring($1)} | |
...		| nocoercions : Rreg_off | |
			  {Rreg_off, %[1.reg],%[1.off]+"+"+tostring($1)} | |
...		| nocoercions : ADDR_EXTERN | |
			       {ADDR_EXTERN, %[1.off]+"+"+tostring($1)} | |
...		| nocoercions : ADDR_LOCAL | |
					     {ADDR_LOCAL, %[1.ind]+$1 } | |
...		| nocoercions : Xbpreg_off | |
				     {Xbpreg_off, %[1.reg], %[1.ind]+$1} | |
...		| nocoercions : Rbpreg_off | |
				     {Rbpreg_off, %[1.reg], %[1.ind]+$1} | |
...		| X_REG |
			"inc %[1]"
			erase(%[1]) setcc(%[1])   | %[1]	| | (1,2)
...		| X_ADDREG | |	  {Xreg_off, %[1], tostring($1)} | |
...		| nocoercions : RADDREG | |  {Rreg_off, %[1], tostring($1)} | |
adp $1 == 0-1	| nocoercions : Xreg_off | |
			      {Xreg_off, %[1.reg],%[1.off]+tostring($1)} | |
...		| nocoercions : Rreg_off | |
			      {Rreg_off, %[1.reg],%[1.off]+tostring($1)} | |
...		| nocoercions : ADDR_EXTERN | |
				   {ADDR_EXTERN, %[1.off]+tostring($1)} | |
...		| nocoercions : ADDR_LOCAL| |{ADDR_LOCAL, %[1.ind]+$1 } | |
...		| nocoercions : Xbpreg_off | |
				     {Xbpreg_off, %[1.reg], %[1.ind]+$1} | |
...		| nocoercions : Rbpreg_off | |
				     {Rbpreg_off, %[1.reg], %[1.ind]+$1} | |
...		| X_REG |
			"dec %[1]"
			erase(%[1]) setcc(%[1])   | %[1]	| | (1,2)
...		| X_ADDREG | |	  {Xreg_off, %[1], tostring($1)} | |
...		| nocoercions : RADDREG | |  {Rreg_off, %[1], tostring($1)} | |
adp		| nocoercions : Xreg_off | |
			  {Xreg_off, %[1.reg],%[1.off]+"+"+tostring($1)} | |
...		| nocoercions : Rreg_off | |
			  {Rreg_off, %[1.reg],%[1.off]+"+"+tostring($1)} | |
...		| nocoercions : ADDR_EXTERN | |
			       {ADDR_EXTERN, %[1.off]+"+"+tostring($1)} | |
...		| nocoercions : ADDR_LOCAL | |
					     {ADDR_LOCAL, %[1.ind]+$1 } | |
...		| nocoercions : Xbpreg_off | |
				     {Xbpreg_off, %[1.reg], %[1.ind]+$1} | |
...		| nocoercions : Rbpreg_off | |
				     {Rbpreg_off, %[1.reg], %[1.ind]+$1} | |
...		| X_ADDREG | |	  	  {Xreg_off, %[1], tostring($1)} | |
...		| nocoercions : RADDREG | |  {Rreg_off, %[1], tostring($1)} | |
...		| X_REG |
			"add %[1],$1"
			erase(%[1]) setcc(%[1]) | %[1]  | | (4,4)
ads $1==2	| nocoercions : ANYCON Rreg_off |  |
			{Rreg_off, %[2.reg],
				%[2.off]+"+"+tostring(%[1.val])}	| |
...		| nocoercions : ADDR_EXTERN Rreg_off | |
			{Rreg_off, %[2.reg], %[2.off]+"+"+%[1.off]}	| |
...		| nocoercions : ANYCON Xreg_off |  |
			{Xreg_off, %[2.reg],
				%[2.off]+"+"+tostring(%[1.val])}	| |
...		| nocoercions : ADDR_EXTERN Xreg_off | |
			{Xreg_off, %[2.reg], %[2.off]+"+"+%[1.off]}	| |
...		| rm Xreg_off |
			"add %[2.reg],%[1]"
			erase(%[2.reg]) setcc(%[2.reg]) |
			  {Xreg_off, %[2.reg], %[2.off]} | | (2,3) + %[1]
...		| nocoercions : ANYCON Xbpreg_off | |
			      {Xbpreg_off, %[2.reg], %[2.ind]+%[1.val]} | |
...		| nocoercions : ANYCON Rbpreg_off | |
			      {Rbpreg_off, %[2.reg], %[2.ind]+%[1.val]} | |
...		| rm Xbpreg_off |
			"add %[2.reg],%[1]"
			erase(%[2.reg]) setcc(%[2.reg]) |
			{Xbpreg_off, %[2.reg], %[2.ind]} | | (2,3) + %[1]
...		| Xreg_off rmorconst |
			"add %[1.reg],%[2]"
			erase(%[1.reg]) setcc(%[1.reg]) |
			  {Xreg_off, %[1.reg], %[1.off]} | | (2,3) + %[2]
...		| Xbpreg_off rmorconst |
			"add %[1.reg],%[2]"
			erase(%[1.reg]) setcc(%[1.reg]) |
			{Xbpreg_off, %[1.reg], %[1.ind]} | | (2,3) + %[2]
...		| nocoercions : Xreg_off ANYCON |  |
			{Xreg_off, %[1.reg],
				  %[1.off]+"+"+tostring(%[2.val])}     | |
...		| nocoercions : Xreg_off ADDR_EXTERN | |
			    {Xreg_off, %[1.reg], %[1.off]+"+"+%[2.off]} | |
...		| nocoercions : Rreg_off ANYCON |  |
			{Rreg_off, %[1.reg],
				  %[1.off]+"+"+tostring(%[2.val])}     | |
...		| nocoercions : Rreg_off ADDR_EXTERN | |
			    {Rreg_off, %[1.reg], %[1.off]+"+"+%[2.off]} | |
...		| nocoercions : Xreg_off reg_off |
			"add %[1.reg],%[2.reg]"
			erase(%[1.reg]) setcc(%[1.reg]) |
	       {Xreg_off,%[1.reg],%[1.off]+"+"+%[2.off]} | | (2,3)
#ifndef REGVARS
...		| IREG ADDR_LOCAL |	  | {bpreg_off,%[1],%[2.ind]} | |
/*
...		| (REG-IREG) ADDR_LOCAL |
			allocate(%[1],ADDREG=%[1])
			"add %[a],bp"
		  | {reg_off, %[a], tostring(%[2.ind])} | | (2,3)
*/
#else
...		| nocoercions: RREG ADDR_LOCAL |	  |
			{Rbpreg_off,%[1],%[2.ind]} | |
#endif
#ifdef DEEPER
...		| X_REG rmorconst |
			"add %[1],%[2]"
			erase(%[1]) setcc(%[1]) | %[1]	| | (2,3) + %[2]
...		| rmorconst X_REG |
			"add %[2],%[1]"
			erase(%[2]) setcc(%[2]) | %[2]	| | (2,3) + %[1]
...		| X_ACC const |
			"add %[1],%[2]"
			erase(%[1]) setcc(%[1]) | %[1]	| | (3,4)
...		| const X_ACC |
			"add %[2],%[1]"
			erase(%[2]) setcc(%[2]) | %[2]	| | (3,4)
#else
...		| X_ADDREG ADDR_EXTERN | |      {Xreg_off, %[1], %[2.off]} | |
...		| X_ADDREG rm |
			"add %[1],%[2]"
			erase(%[1]) setcc(%[1]) | %[1]	| | (2,3) + %[2]
...		| ADDR_EXTERN X_ADDREG | |      {Xreg_off, %[2], %[1.off]} | |
...		| rm X_ADDREG |
			"add %[2],%[1]"
			erase(%[2]) setcc(%[2]) | %[2]	| | (2,3) + %[1]
#endif
sbs $1==2	| nocoercions : ANYCON Xreg_off |   |
		   {Xreg_off, %[2.reg], %[2.off]+"-"+tostring(%[1.val])} | |
...		| nocoercions : ANYCON Rreg_off |   |
		   {Rreg_off, %[2.reg], %[2.off]+"-"+tostring(%[1.val])} | |
...		| nocoercions : ANYCON ADDR_LOCAL | |
					{ADDR_LOCAL, %[2.ind]-%[1.val]} | |
...		| rm Xreg_off |
			"sub %[2.reg],%[1]"
			erase(%[2.reg]) setcc(%[2.reg]) |
					  {Xreg_off, %[2.reg], %[2.off]} | |
/*	Should not occur
...		| nocoercions : reg_off ANYCON |   |
		   {reg_off, %[1.reg], %[1.off]+"-"+tostring(%[2.val])} | |
...		| ANYCON ADDR_EXTERN | |
			 {ADDR_EXTERN, %[2.off]+"+"+tostring(%[1.val])} | |
...		| nocoercions : ANYCON ADDR_LOCAL | |
				        {ADDR_LOCAL, %[1.val]+%[2.ind]} | |
*/
...		| rm X_REG |
			"sub %[2],%[1]"
			erase(%[2]) setcc(%[2]) | %[2]	| | (2,3) + %[1]
...		| const X_ACC |
			"sub %[2],%[1]"
			erase(%[2]) setcc(%[2]) | %[2]	| | (3,4)

/****************************************
 * Group 7 : increment/decrement/zero	*
 ****************************************/

inc		| X_REG |
			"inc %[1]"
			setcc(%[1]) erase(%[1])      | %[1] | |(1,2)
#ifdef REGVARS
inl inreg($1)==2| |
			remove(regvar($1))
			"inc %(regvar($1)%)"
			erase(regvar($1)) setcc(regvar($1))	     |	    | |(1,2)
#endif
inl		| |	remove(indexed)
			remove(locals, %[ind]>=$1 && %[ind]<$1+2 )
			"inc $1(bp)"
			setcc({LOCAL2,$1,2})	     |	    | |(3,24)
ine		| |	remove(indirects)
			"inc ($1)"
			setcc({EXTERN2,$1})	     |	    | |(4,21)
dec		| X_REG |
			"dec %[1]"
			setcc(%[1]) erase(%[1])      | %[1] | |(1,2)
#ifdef REGVARS
del inreg($1)==2| |
			remove(regvar($1))
			"dec %(regvar($1)%)"
			erase(regvar($1)) setcc(regvar($1))	     |	    | |(1,2)
#endif
del		| |	remove(indexed)
			remove(locals, %[ind]>=$1 && %[ind]<$1+2 )
			"dec $1(bp)"
			setcc({LOCAL2,$1,2})	     |	    | |(3,24)
dee		| |	remove(indirects)
			"dec ($1)"
			setcc({EXTERN2,$1})	     |	    | |(4,21)
#ifdef REGVARS
zrl inreg($1)==2| |
			remove(regvar($1))
			move({ANYCON,0},regvar($1))
			erase(regvar($1)) 	|	| |
#endif
zrl		| |	remove(indexed)
			remove(locals, %[ind]>=$1 && %[ind]<$1+2 )
			move({ANYCON,0},{LOCAL2,$1,2})
						     |	    | |
zre		| |	remove(indirects)
			move({ANYCON,0},{EXTERN2,$1})|	    | |
zer $1==2	| |			       | {ANYCON,0} | |
zer $1==4	| |		    | {ANYCON,0} {ANYCON,0} | |
zer $1==6	| |		    | {ANYCON,0} {ANYCON,0}
						 {ANYCON,0} | |
zer $1==8	| |		    | {ANYCON,0} {ANYCON,0}
				      {ANYCON,0} {ANYCON,0} | |
zer defined($1) | |	remove(ALL)
			move({ANYCON,$1/2},cx)
			move({ANYCON,0},bx)
			"1: push bx"
			"loop 1b"
			samecc erase(cx)		  | | |(3,10+$1*4)
zer !defined($1)| X_CXREG |
			remove(ALL)
			move({ANYCON,0},bx)
			"sar cx,1"
			"1:\tpush bx"
			"loop 1b"
			samecc erase(%[1])		  | | |

#ifdef REGVARS
lol adi stl $1==$3 && $2==2 && inreg($1)==2 | rmorconst |
			remove(regvar($1))
			"add %(regvar($1)%),%[1]"
			erase(regvar($1)) setcc(regvar($1))		  | | |
#endif
lol adi stl $1==$3 && $2==2 | regorconst |
			remove(indexed)
			remove(locals, %[ind]>=$1 && %[ind]<$1+2 )
			"add $1(bp),%[1]"
			setcc({LOCAL2, $1, 2})		  | | |
ldl adi sdl $1==$3 && $2==4 | regorconst regorconst |
			remove(indexed)
			remove(locals, %[ind]>=$1 && %[ind]<$1+4 )
			"add $1(bp),%[1]"
			"adc %($1+2%)(bp),%[2]"		   | | |
#ifdef REGVARS
lol loc sbi stl $1==$4 && $3==2 && inreg($1)==2 | |
			remove(regvar($1))
			"sub %(regvar($1)%),$2"
			erase(regvar($1)) setcc(regvar($1))		   | | |
#endif
lol loc sbi stl $1==$4 && $3==2 | |
			remove(indexed)
			remove(locals, %[ind]>=$1 && %[ind]<$1+2 )
			"sub $1(bp),$2"
			setcc({LOCAL2, $1, 2})		  | | |
#ifdef REGVARS
lol loc sli stl $1==$4 && $2==1 && $3==2 && inreg($1)==2 | |
			remove(regvar($1))
			"sal %(regvar($1)%),1"
			erase(regvar($1)) setcc(regvar($1))		| | |
lol loc sli stl $1==$4 && $2==2 && $3==2 && inreg($1)==2 | |
			remove(regvar($1))
			"sal %(regvar($1)%),1"
			"sal %(regvar($1)%),1"
			erase(regvar($1)) setcc(regvar($1))		| | |
lol loc sli stl $1==$4 && $3==2 && inreg($1)==2 | |
			remove(regvar($1))
			allocate(CXREG = {ANYCON, $2})
			"sal %(regvar($1)%),cl"
			erase(regvar($1)) setcc(regvar($1))		| | |
lol loc sri stl $1==$4 && $2==1 && $3==2 && inreg($1)==2 | |
			remove(regvar($1))
			"sar %(regvar($1)%),1"
			erase(regvar($1)) setcc(regvar($1))		| | |
lol loc sri stl $1==$4 && $2==2 && $3==2 && inreg($1)==2 | |
			remove(regvar($1))
			"sar %(regvar($1)%),1"
			"sar %(regvar($1)%),1"
			erase(regvar($1)) setcc(regvar($1))		| | |
lol loc sri stl $1==$4 && $3==2 && inreg($1)==2 | |
			remove(regvar($1))
			allocate(CXREG = {ANYCON, $2})
			"sar %(regvar($1)%),cl"
			erase(regvar($1)) setcc(regvar($1))		| | |
#endif
#ifdef REGVARS
lol ngi stl $1==$3 && $2==2 && inreg($1)==2 | |
			remove(regvar($1))
			"neg %(regvar($1)%)"
			erase(regvar($1)) setcc(regvar($1))		  | | |
#endif
lol ngi stl $1==$3 && $2==2 | |
			remove(indexed)
			remove(locals, %[ind]>=$1 && %[ind]<$1+2 )
			"neg $1(bp)"
			setcc({LOCAL2, $1, 2})		  | | |
ldl ngi sdl $1==$3 && $2==4 | |
			remove(indexed)
			remove(locals, %[ind]>=$1 && %[ind]<$1+4 )
			"neg $1(bp)"
			"neg %($1+2%)(bp)"
			"sbb %($1+2%)(bp),0"		  | | |
lol ads stl $1==$3 && $2==2 | | | | lol $1 adi 2 stl $1 |
#ifdef REGVARS
lol lol adp stl $1==$2 && $1==$4 && inreg($1)==2 | |
			allocate(ADDREG=regvar($1))	| %[a] | lol $2 adp $3 stl $2 |
lol inl $1==$2 && inreg($1)==2 | |
			allocate(REG=regvar($1))	  | %[a] | inl $1 |
lol del $1==$2 && inreg($1)==2 | |
			allocate(REG=regvar($1))	  | %[a] | del $1 |
#endif
lol lol adp stl $1==$2 && $1==$4 | |
			allocate(ADDREG={LOCAL2,$1,2})	  | %[a] | lol $2 adp $3 stl $2 |
lol inl $1==$2 | |	allocate(REG={LOCAL2,$1,2})	  | %[a] | inl $1 |
lol del $1==$2 | |	allocate(REG={LOCAL2,$1,2})	  | %[a] | del $1 |
lol adp stl $1==$3 && $2==1 | | | | inl $1 |
lol adp stl $1==$3 && $2==0-1 | | | | del $1 |
#ifdef REGVARS
lol adp stl $1==$3 && inreg($1)==2    | |
			remove(regvar($1))
			"add %(regvar($1)%),$2"
			erase(regvar($1)) setcc(regvar($1))		  | | |
#endif
lol adp stl $1==$3	    | |
			remove(indexed)
			remove(locals, %[ind]>=$1 && %[ind]<$1+2 )
			"add $1(bp),$2"
			setcc({LOCAL2, $1, 2})		  | | |
#ifdef REGVARS
lol and stl $1==$3 && $2==2 && inreg($1)==2 | rmorconst |
			remove(regvar($1))
			"and %(regvar($1)%),%[1]"
			erase(regvar($1)) setcc(regvar($1))		  | | |
#endif
lol and stl $1==$3 && $2==2 | regorconst |
			remove(indexed)
			remove(locals, %[ind]>=$1 && %[ind]<$1+2 )
			"and $1(bp),%[1]"
			setcc({LOCAL2, $1, 2})		  | | |
#ifdef REGVARS
lol ior stl $1==$3 && $2==2 && inreg($1)==2 | rmorconst |
			remove(regvar($1))
			"or %(regvar($1)%),%[1]"
			erase(regvar($1)) setcc(regvar($1))		  | | |
#endif
lol ior stl $1==$3 && $2==2 | regorconst |
			remove(indexed)
			remove(locals, %[ind]>=$1 && %[ind]<$1+2 )
			"or $1(bp),%[1]"
			setcc({LOCAL2, $1, 2})		  | | |
#ifdef REGVARS
lol com stl $1==$3 && $2==2 && inreg($1)==2 | |
			remove(regvar($1))
			"not %(regvar($1)%)"
			erase(regvar($1)) samecc				  | | |
#endif
lol com stl $1==$3 && $2==2 | |
			remove(indexed)
			remove(locals, %[ind]>=$1 && %[ind]<$1+2 )
			"not $1(bp)"
			samecc				  | | |
#ifdef REGVARS
lil adi sil $1==$3 && $2==2 && inreg($1)==2 | regorconst |
			remove(referals)
			"add (%(regvar($1)%)),%[1]"
			setcc({ind_reg2, regvar($1)})		  | | |
#endif
lil adi sil $1==$3 && $2==2 | regorconstnoaddr |
			allocate(ADDREG={LOCAL2, $1, 2})
			remove(referals)
			"add (%[a]),%[1]"
			setcc({ind_reg2, %[a]})		  | | |
#ifdef REGVARS
lil ngi sil $1==$3 && $2==2 && inreg($1)==2 | |
			remove(referals)
			"neg (%(regvar($1)%))"
			setcc({ind_reg2, regvar($1)})		  | | |
#endif
lil ngi sil $1==$3 && $2==2 | |
			allocate(ADDREG={LOCAL2, $1, 2})
			remove(referals)
			"neg (%[a])"
			setcc({ind_reg2, %[a]})		  | | |
lil ads sil $1==$3 && $2==2 | | | | lil $1 adi 2 sil $1 |
#ifdef REGVARS
lil adp sil $1==$3 && $2==1 && inreg($1)==2 | |
			remove(referals)
			"inc (%(regvar($1)%))"
			setcc({ind_reg2, regvar($1)})		  | | |
#endif
lil adp sil $1==$3 && $2==1 | |
			allocate(ADDREG={LOCAL2, $1, 2})
			remove(referals)
			"inc (%[a])"
			setcc({ind_reg2, %[a]})		  | | |
#ifdef REGVARS
lil adp sil $1==$3 && $2==0-1 && inreg($1)==2 | |
			remove(referals)
			"dec (%(regvar($1)%))"
			setcc({ind_reg2, regvar($1)})		  | | |
#endif
lil adp sil $1==$3 && $2==0-1 | |
			allocate(ADDREG={LOCAL2, $1, 2})
			remove(referals)
			"dec (%[a])"
			setcc({ind_reg2, %[a]})		  | | |
#ifdef REGVARS
lil adp sil $1==$3 && inreg($1)==2 | |
			remove(referals)
			"add (%(regvar($1)%)),$2"
			setcc({ind_reg2, regvar($1)})		  | | |
#endif
lil adp sil $1==$3	    | |
			allocate(ADDREG={LOCAL2, $1, 2})
			remove(referals)
			"add (%[a]),$2"
			setcc({ind_reg2, %[a]})		  | | |
#ifdef REGVARS
lil and sil $1==$3 && $2==2 && inreg($1)==2 | regorconst |
			remove(referals)
			"and (%(regvar($1)%)),%[1]"
			setcc({ind_reg2, regvar($1)})		  | | |
#endif
lil and sil $1==$3 && $2==2 | regorconstnoaddr |
			allocate(ADDREG={LOCAL2, $1, 2})
			remove(referals)
			"and (%[a]),%[1]"
			setcc({ind_reg2, %[a]})		  | | |
#ifdef REGVARS
lil ior sil $1==$3 && $2==2 && inreg($1)==2 | regorconst |
			remove(referals)
			"or (%(regvar($1)%)),%[1]"
			setcc({ind_reg2, regvar($1)})		  | | |
#endif
lil ior sil $1==$3 && $2==2 | regorconstnoaddr |
			allocate(ADDREG={LOCAL2, $1, 2})
			remove(referals)
			"or (%[a]),%[1]"
			setcc({ind_reg2, %[a]})		  | | |
#ifdef REGVARS
lil com sil $1==$3 && $2==2 && inreg($1)==2 | |
			remove(referals)
			"not (%(regvar($1)%))"
			samecc				  | | |
#endif
lil com sil $1==$3 && $2==2 | |
			allocate(ADDREG={LOCAL2, $1, 2})
			remove(referals)
			"not (%[a])"
			samecc				  | | |
#ifdef REGVARS
lol lof adi lol stf $1==$4 && $2==$5 && $3==2 && inreg($1)==2 | regorconst |
			remove(referals)
			"add $2(%(regvar($1)%)),%[1]"
			setcc({ind_regoff2, regvar($1), tostring($2)})  | | |
#endif
lol lof adi lol stf $1==$4 && $2==$5 && $3==2 | regorconstnoaddr |
			allocate(ADDREG={LOCAL2, $1, 2})
			remove(referals)
			"add $2(%[a]),%[1]"
			setcc({ind_regoff2, %[a], tostring($2)}) | | |
#ifdef REGVARS
lol lof ngi lol stf $1==$4 && $2==$5 && $3==2 && inreg($1)==2 | |
			remove(referals)
			"neg $2(%(regvar($1)%))"
			setcc({ind_regoff2, regvar($1), tostring($2)})  | | |
#endif
lol lof ngi lol stf $1==$4 && $2==$5 && $3==2 | |
			allocate(ADDREG={LOCAL2, $1, 2})
			remove(referals)
			"neg $2(%[a])"
			setcc({ind_regoff2, %[a], tostring($2)})  | | |
lol lof ads lol stf $1==$4 && $2==$5 && $3==2 | | | | lol $1 lof $2 adi 2 lol $1 stf $2 |
#ifdef REGVARS
lol lof adp lol stf $1==$4 && $2==$5 && $3==1 && inreg($1)==2 | |
			remove(referals)
			"inc $2(%(regvar($1)%))"
			setcc({ind_regoff2, regvar($1), tostring($2)})  | | |
#endif
lol lof adp lol stf $1==$4 && $2==$5 && $2==1 | |
			allocate(ADDREG={LOCAL2, $1, 2})
			remove(referals)
			"inc $2(%[a])"
			setcc({ind_regoff2, %[a], tostring($2)})  | | |
#ifdef REGVARS
lol lof adp lol stf $1==$4 && $2==$5 && $3==0-1 && inreg($1)==2 | |
			remove(referals)
			"dec $2(%(regvar($1)%))"
			setcc({ind_regoff2, regvar($1), tostring($2)})  | | |
#endif
lol lof adp lol stf $1==$4 && $2==$5 && $3==0-1 | |
			allocate(ADDREG={LOCAL2, $1, 2})
			remove(referals)
			"dec $2(%[a])"
			setcc({ind_regoff2, %[a], tostring($2)})  | | |
#ifdef REGVARS
lol lof adp lol stf $1==$4 && $2==$5 && inreg($1)==2 | |
			remove(referals)
			"add $2(%(regvar($1)%)),$3"
			setcc({ind_regoff2, regvar($1),tostring($2)})  | | |
#endif
lol lof adp lol stf $1==$4 && $2==$5	    | |
			allocate(ADDREG={LOCAL2, $1, 2})
			remove(referals)
			"add $2(%[a]),$3"
			setcc({ind_regoff2, %[a], tostring($2)})  | | |
#ifdef REGVARS
lol lof and lol stf $1==$4 && $2==$5 && $3==2 && inreg($1)==2 | regorconst |
			remove(referals)
			"and $2(%(regvar($1)%)),%[1]"
			setcc({ind_regoff2, regvar($1), tostring($2)})  | | |
#endif
lol lof and lol stf $1==$4 && $2==$5 && $3==2 | regorconstnoaddr |
			allocate(ADDREG={LOCAL2, $1, 2})
			remove(referals)
			"and $2(%[a]),%[1]"
			setcc({ind_regoff2, %[a], tostring($2)})  | | |
#ifdef REGVARS
lol lof ior lol stf $1==$4 && $2==$5 && $3==2 && inreg($1)==2 | regorconst |
			remove(referals)
			"or $2(%(regvar($1)%)),%[1]"
			setcc({ind_regoff2, regvar($1), tostring($2)})  | | |
#endif
lol lof ior lol stf $1==$4 && $2==$5 && $3==2 | regorconstnoaddr |
			allocate(ADDREG={LOCAL2, $1, 2})
			remove(referals)
			"or $2(%[a]),%[1]"
			setcc({ind_regoff2, %[a], tostring($2)})  | | |
#ifdef REGVARS
lol lof com lol stf $1==$4 && $2==$5 && $3==2 && inreg($1)==2 | |
			remove(referals)
			"not $2(%(regvar($1)%))"
			samecc				  | | |
#endif
lol lof com lol stf $1==$4 && $2==$5 && $3==2 | |
			allocate(ADDREG={LOCAL2, $1, 2})
			remove(referals)
			"not $2(%[a])"
			samecc				  | | |
loe adi ste $1==$3 && $2==2 | regorconst |
			remove(indirects)
			"add ($1),%[1]"
			setcc({EXTERN2, $1})		  | | |
lde adi sde $1==$3 && $2==4 | regorconst regorconst |
			remove(indirects)
			"add ($1),%[1]"
			"adc ($1+2),%[2]"		  | | |
loe ngi ste $1==$3 && $2==2 | |
			remove(indirects)
			"neg ($1)"
			setcc({EXTERN2, $1})		  | | |
lde ngi sde $1==$3 && $2==4 | |
			remove(indirects)
			"neg ($1)"
			"neg ($1+2)"
			"sbb ($1+2),0"			  | | |
loe ads ste $1==$3 && $2==2 | regorconst |
			remove(indirects)
			"add ($1),%[1]"
			setcc({EXTERN2, $1})		  | | |
loe loe adp ste $1==$4 && $1==$4 | |
			allocate(ADDREG={EXTERN2,$1})	| %[a] | loe $1 adp $3 ste $1 |
loe ine $1==$2 | |	allocate(REG={EXTERN2,$1})	| %[a] | ine $1 |
loe dee $1==$2 | |	allocate(REG={EXTERN2,$1})	| %[a] | dee $1 |
loe adp ste $1==$3 && $2==1 | |
			remove(indirects)
			"inc ($1)"
			setcc({EXTERN2, $1})		  | | |
loe adp ste $1==$3 && $2==0-1 | |
			remove(indirects)
			"dec ($1)"
			setcc({EXTERN2, $1})		  | | |
loe adp ste $1==$3 	    | |
			remove(indirects)
			"add ($1),$2"
			setcc({EXTERN2, $1})		  | | |
loe and ste $1==$3 && $2==2 | regorconst |
			remove(indirects)
			"and ($1),%[1]"
			setcc({EXTERN2, $1})		  | | |
loe ior ste $1==$3 && $2==2 | regorconst |
			remove(indirects)
			"or ($1),%[1]"
			setcc({EXTERN2, $1})		  | | |
loe com ste $1==$3 && $2==2 | |
			remove(indirects)
			"not ($1)"
			samecc				  | | |
loe lof adi loe stf $1==$4 && $2==$5 && $3==2 | regorconstnoaddr |
			allocate(ADDREG={EXTERN2, $1})
			remove(referals)
			"add $2(%[a]),%[1]"
			setcc({ind_regoff2, %[a], tostring($2)}) | | |
loe lof ngi loe stf $1==$4 && $2==$5 && $3==2 | |
			allocate(ADDREG={EXTERN2, $1})
			remove(referals)
			"neg $2(%[a])"
			setcc({ind_regoff2, %[a], tostring($2)})  | | |
loe lof ads loe stf $1==$4 && $2==$5 && $3==2 | | | | loe $1 lof $2 adi 2 loe $1 stf $2 |
loe lof adp loe stf $1==$4 && $2==$5 && $2==1 | |
			allocate(ADDREG={EXTERN2, $1})
			remove(referals)
			"inc $2(%[a])"
			setcc({ind_regoff2, %[a], tostring($2)})  | | |
loe lof adp loe stf $1==$4 && $2==$5 && $3==0-1 | |
			allocate(ADDREG={EXTERN2, $1})
			remove(referals)
			"dec $2(%[a])"
			setcc({ind_regoff2, %[a], tostring($2)})  | | |
loe lof adp loe stf $1==$4 && $2==$5	    | |
			allocate(ADDREG={EXTERN2, $1})
			remove(referals)
			"add $2(%[a]),$3"
			setcc({ind_regoff2, %[a], tostring($2)})  | | |
loe lof and loe stf $1==$4 && $2==$5 && $3==2 | regorconstnoaddr |
			allocate(ADDREG={EXTERN2, $1})
			remove(referals)
			"and $2(%[a]),%[1]"
			setcc({ind_regoff2, %[a], tostring($2)})  | | |
loe lof ior loe stf $1==$4 && $2==$5 && $3==2 | regorconstnoaddr |
			allocate(ADDREG={EXTERN2, $1})
			remove(referals)
			"or $2(%[a]),%[1]"
			setcc({ind_regoff2, %[a], tostring($2)})  | | |
loe lof com loe stf $1==$4 && $2==$5 && $3==2 | |
			allocate(ADDREG={EXTERN2, $1})
			remove(referals)
			"not $2(%[a])"
			samecc				  | | |

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

cii		| CXREG DXREG X_ACC |
			remove(ALL)
			"call .cii"
			erase(%[3])		     | %[3] | |
ciu		| |		|			| cuu	|
cui		| |		|			| cuu	|
cuu		| CXREG DXREG X_ACC |
			remove(ALL)
			"call .cuu"
			erase(%[3])		     | %[3] | |
loc loc cii $1==1 && $2==2	| X_ACC |
			 "cbw"
			 samecc 		    | ax  | |(1,2)
...				| nocoercions: rmorconst1 |
			allocate(%[1], ACC1 = %[1])
			 "cbw"
			 samecc			    | ax  | |(1,2)
loc loc cii $1==1 && $2==4	| X_ACC |
			allocate(DXREG)
			"cbw"
			"cwd"
			samecc			    | %[a] ax | |(2,7)
...				| nocoercions: rmorconst1 |
			allocate(%[1], ACC1 = %[1], DXREG)
			"cbw"
			"cwd"
			samecc			    | dx ax | |(2,7)
loc loc cii $1==2 && $2==4	| ACC |
			allocate(DXREG)
			"cwd"
			samecc			    | %[a] ax | |(1,5)
loc loc cii $1==4 && $2==2	| a_word a_word |    | %[1] | |
loc loc ciu	| |		|			| loc $1 loc $2 cuu |
loc loc cui	| |		|			| loc $1 loc $2 cuu |
loc loc cuu $1==$2		| |		|	|	|
loc loc cuu $1==2 && $2==4	| a_word |	| {ANYCON,0} %[1] | |
loc loc cuu $1==4 && $2==2	| a_word a_word |    | %[1] | |

/*
 * Floating point stuff
 * Conversion
 */
loc loc cif	$1==2 && $2==4 | |
			remove(ALL)
			"mov ax,$1"
			"push ax"		| | cal ".cif4" |
loc loc cif	$1==4 && $2==4 | |
			remove(ALL)
			"mov ax,$1"
			"push ax"		| | cal ".cif4" asp 2 |
loc loc cif	$1==2 && $2==8 | X_REG |
			remove(ALL)
			"push %[1]"
			"push %[1]"
			"push %[1]"
			"mov ax,$1"
			"push ax"		| | cal ".cif8" |
loc loc cif	$1==4 && $2==8 | X_REG X_REG |
			remove(ALL)
			"push %[1]"
			"push %[2]"
			"push %[1]"
			"mov ax,$1"
			"push ax"		| | cal ".cif8" |
loc loc cuf	$1==2 && $2==4 | |
			remove(ALL)
			"mov ax,$1"
			"push ax"		| | cal ".cuf4" |
loc loc cuf	$1==4 && $2==4 | |
			remove(ALL)
			"mov ax,$1"
			"push ax"		| | cal ".cuf4" asp 2 |
loc loc cuf	$1==2 && $2==8 | X_REG |
			remove(ALL)
			"push %[1]"
			"push %[1]"
			"push %[1]"
			"mov ax,$1"
			"push ax"		| | cal ".cuf8" |
loc loc cuf	$1==4 && $2==8 | X_REG X_REG |
			remove(ALL)
			"push %[1]"
			"push %[2]"
			"push %[1]"
			"mov ax,$1"
			"push ax"		| | cal ".cuf8" |
loc loc cfi	$1==4 && $2==2 | |
			remove(ALL)
			"mov ax,$1"
			"push ax"
			"mov ax,$2"
			"push ax"		| | cal ".cfi" asp 8 lfr 2 |
loc loc cfi	$1==4 && $2==4 | |
			remove(ALL)
			"mov ax,$1"
			"push ax"
			"mov ax,$2"
			"push ax"		| | cal ".cfi" asp 4 |
loc loc cfi	$1==8 && $2==2 | |
			remove(ALL)
			"mov ax,$1"
			"push ax"
			"mov ax,$2"
			"push ax"		| | cal ".cfi" asp 12 lfr 2 |
loc loc cfi	$1==8 && $2==4 | |
			remove(ALL)
			"mov ax,$1"
			"push ax"
			"mov ax,$2"
			"push ax"		| | cal ".cfi" asp 8 |
loc loc cfu	$1==4 && $2==2 | |
			remove(ALL)
			"mov ax,$1"
			"push ax"
			"mov ax,$2"
			"push ax"		| | cal ".cfu" asp 8 lfr 2 |
loc loc cfu	$1==4 && $2==4 | |
			remove(ALL)
			"mov ax,$1"
			"push ax"
			"mov ax,$2"
			"push ax"		| | cal ".cfu" asp 4 |
loc loc cfu	$1==8 && $2==2 | |
			remove(ALL)
			"mov ax,$1"
			"push ax"
			"mov ax,$2"
			"push ax"		| | cal ".cfu" asp 12 lfr 2 |
loc loc cfu	$1==8 && $2==4 | |
			remove(ALL)
			"mov ax,$1"
			"push ax"
			"mov ax,$2"
			"push ax"		| | cal ".cfu" asp 8 |
loc loc cff	$1==8 && $2==4 | |
			remove(ALL)		| | cal ".cff4" asp 4 |
loc loc cff	$1==4 && $2==8 | X_REG X_REG |
			remove(ALL)
			allocate(REG)
			"xor %[a],%[a]"
			"push %[a]"
			"push %[a]"
			"push %[2]"
			"push %[1]"		| | cal ".cff8" |

/****************************************
 * Group 9 : Logical instructions	*
 ****************************************/

and $1==2	| NO X_REG rmorconst |
			"and %[1],%[2]"
			erase(%[1]) setcc(%[1]) | %[1]	| | (2,3) + %[2]
...		| rmorconst X_REG |
			"and %[2],%[1]"
			erase(%[2]) setcc(%[2]) | %[2]	| | (2,3) + %[1]
...		| X_ACC const |
			"and %[1],%[2]"
			erase(%[1]) setcc(%[1]) | %[1]	| | (3,4)
...		| const X_ACC |
			"and %[2],%[1]"
			erase(%[2]) setcc(%[2]) | %[2]	| | (3,4)
and $1==4	| NO X_REG X_REG rmorconst rmorconst |
			"and %[1],%[3]"
			"and %[2],%[4]"
			setcc(%[2]) erase(%[1]) erase(%[2])
						| %[2] %[1] | |(4,6)+%[4]+%[3]
...		| nocoercions: X_ACC X_REG const rmorconst |
			"and %[1],%[3]"
			"and %[2],%[4]"
			setcc(%[2]) erase(%[1]) erase(%[2])
						| %[2] %[1] | |(5,7)+%[4]
...		| rmorconst rmorconst X_REG X_REG |
			"and %[3],%[1]"
			"and %[4],%[2]"
			setcc(%[4]) erase(%[3]) erase(%[4])
						| %[4] %[3] | |(4,6)+%[1]+%[2]
...		| nocoercions: const rmorconst-ACC X_ACC X_REG |
			"and %[3],%[1]"
			"and %[4],%[2]"
			setcc(%[4]) erase(%[3]) erase(%[4])
						| %[4] %[3] | |(5,7)+%[2]
and defined($1) | |	remove(ALL)
			"mov cx,$1"
			"call .and"			  | | |
and !defined($1)| X_CXREG |
			remove(ALL)
			"call .and"
			erase(%[1])			  | | |
ior $1==2	| X_REG rmorconst |
			"or %[1],%[2]"
			erase(%[1]) setcc(%[1]) | %[1]	| | (2,3) + %[2]
...		| NO rmorconst X_REG |
			"or %[2],%[1]"
			erase(%[2]) setcc(%[2]) | %[2]	| | (2,3) + %[1]
...		| X_ACC const |
			"or %[1],%[2]"
			erase(%[1]) setcc(%[1]) | %[1]	| | (3,4)
...		| const X_ACC |
			"or %[2],%[1]"
			erase(%[2]) setcc(%[2]) | %[2]	| | (3,4)
ior $1==4	| NO X_REG X_REG rmorconst rmorconst |
			"or %[1],%[3]"
			"or %[2],%[4]"
			setcc(%[2]) erase(%[1]) erase(%[2])
						| %[2] %[1] | |(4,6)+%[4]+%[3]
...		| nocoercions: X_ACC X_REG const rmorconst |
			"or %[1],%[3]"
			"or %[2],%[4]"
			setcc(%[2]) erase(%[1]) erase(%[2])
						| %[2] %[1] | |(5,7)+%[4]
...		| rmorconst rmorconst X_REG X_REG |
			"or %[3],%[1]"
			"or %[4],%[2]"
			setcc(%[4]) erase(%[3]) erase(%[4])
						| %[4] %[3] | |(4,6)+%[1]+%[2]
...		| nocoercions: const rmorconst-ACC X_ACC X_REG |
			"or %[3],%[1]"
			"or %[4],%[2]"
			setcc(%[4]) erase(%[3]) erase(%[4])
						| %[4] %[3] | |(5,7)+%[2]
ior defined($1) | |	remove(ALL)
			"mov cx,$1"
			"call .ior"			  | | |
ior !defined($1)| X_CXREG |
			remove(ALL)
			"call .ior"
			erase(%[1])			  | | |
xor $1==2	| NO X_REG rmorconst |
			"xor %[1],%[2]"
			erase(%[1]) setcc(%[1]) | %[1]	| | (2,3) + %[2]
...		| rmorconst X_REG |
			"xor %[2],%[1]"
			erase(%[2]) setcc(%[2]) | %[2]	| | (2,3) + %[1]
...		| X_ACC const |
			"xor %[1],%[2]"
			erase(%[1]) setcc(%[1]) | %[1]	| | (3,4)
...		| const X_ACC |
			"xor %[2],%[1]"
			erase(%[2]) setcc(%[2]) | %[2]	| | (3,4)
xor $1==4	| NO X_REG X_REG rmorconst rmorconst |
			"xor %[1],%[3]"
			"xor %[2],%[4]"
			setcc(%[2]) erase(%[1]) erase(%[2])
						| %[2] %[1] | |(4,6)+%[4]+%[3]
...		| nocoercions: X_ACC X_REG const rmorconst |
			"xor %[1],%[3]"
			"xor %[2],%[4]"
			setcc(%[2]) erase(%[1]) erase(%[2])
						| %[2] %[1] | |(5,7)+%[4]
...		| rmorconst rmorconst X_REG X_REG |
			"xor %[3],%[1]"
			"xor %[4],%[2]"
			setcc(%[4]) erase(%[3]) erase(%[4])
						| %[4] %[3] | |(4,6)+%[1]+%[2]
...		| nocoercions: const rmorconst-ACC X_ACC X_REG |
			"xor %[3],%[1]"
			"xor %[4],%[2]"
			setcc(%[4]) erase(%[3]) erase(%[4])
						| %[4] %[3] | |(5,7)+%[2]
xor defined($1) | |	remove(ALL)
			"mov cx,$1"
			"call .xor"			  | | |
xor !defined($1)| X_CXREG |
			remove(ALL)
			"call .xor"
			erase(%[1])			  | | |
com $1==2	| X_REG |
			"not %[1]"
			samecc erase(%[1])	    | %[1]  | |(2,3)
com $1==4	| X_REG X_REG |
			"not %[2]"
			"not %[1]"
			samecc erase(%[1]) erase(%[2])
						| %[2] %[1] | |(4,6)
com defined($1) | |	remove(ALL)
			"mov cx,$1"
			"call .com"			  | | |
com !defined($1)| X_CXREG |
			remove(ALL)
			"call .com"
			erase(%[1])			  | | |
loc rol $1==1 && $2==2 | X_REG |
			"rol %[1],1"
			samecc erase(%[1])	     | %[1] | | (2,2)
rol $1==2	| SHIFT_CREG X_REG |
			"rol %[2],cl"
			samecc erase(%[2])	     | %[2] | | (2,8)
rol $1==4	| X_CXREG X_REG X_REG |
			"jcxz 1f"
			"2: sal %[2],1"
			"rcl %[3],1"
			"adc %[2],0"
			"loop 2b\n1:"
			erase(%[1]) erase(%[2]) erase(%[3])
						| %[3] %[2] | |
/*
rol !defined($1)| X_CXREG |
			remove(ALL)
			"call .rol"		    |	    | |
*/
loc ror $1==1 && $2==2 | X_REG |
			"ror %[1],1"
			samecc erase(%[1])	     | %[1] | | (2,2)
ror $1==2	| SHIFT_CREG X_REG |
			"ror %[2],cl"
			samecc erase(%[2])	     | %[2] | | (2,8)
ror $1==4	| X_CXREG X_REG X_REG |
			"jcxz 1f"
			"neg cx"
			"add cx,32"
			"2: sal %[2],1"
			"rcl %[3],1"
			"adc %[2],0"
			"loop 2b\n1:"
			erase(%[1]) erase(%[2]) erase(%[3])
						| %[3] %[2] | |
/*
ror !defined($1)| X_CXREG |
			remove(ALL)
			"call .ror"		    |	    | |
*/

/********************************
 * Group 10 : Set instructions	*
 ********************************/

inn $1==2	| SHIFT_CREG X_REG |
			"shr %[2],cl"
			"and %[2],1"
			setcc(%[2]) erase(%[2])      | %[2] | |(6,13)
...		| SHIFT_CREG X_ACC |
			"shr %[2],cl"
			"and %[2],1"
			setcc(%[2]) erase(%[2])      | %[2] | |(5,13)
loc inn $1==1 && $2==2 | X_REG |
			"shr %[1],1"
			"and %[1],1"
			setcc(%[1]) erase(%[1])      | %[1] | |(6,6)
...		    | X_ACC |
			"shr %[1],1"
			"and %[1],1"
			setcc(%[1]) erase(%[1])      | %[1] | |(5,6)
loc inn $1==0 && $2==2 | X_REG |
			"and %[1],1"
			setcc(%[1]) erase(%[1])      | %[1] | |(6,6)
...		    | X_ACC |
			"and %[1],1"
			setcc(%[1]) erase(%[1])      | %[1] | |(5,6)
inn defined($1) | X_ACC |
			remove(ALL)
			move({ANYCON,$1},cx)
			"call .inn"
			erase(ax)		       | ax | |
inn !defined($1)| CXREG X_ACC |
			remove(ALL)
			"call .inn"
			erase(%[2])		       | ax | |
loc inn zeq $2==2 | rm STACK |
			"test %[1],%(1<<$1%)"
			"je $3" 		       |    | |
loc inn zne $2==2 | rm STACK |
			"test %[1],%(1<<$1%)"
			"jne $3"		       |    | |
set $1==2	| SHIFT_CREG |
			allocate(REG={ANYCON,1})
			"shl %[a],cl"
			setcc(%[a]) erase(%[a])        | %[a] | |
set defined($1) | X_ACC |
			remove(ALL)
			move({ANYCON,$1},cx)
			"call .set"
			erase(%[1])		       |      | |
set !defined($1)| CXREG X_ACC |
			remove(ALL)
			"call .set"
			erase(%[2])		       |      | |

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

lae aar $2==2 && rom(1,3)==1 && rom(1,1)==0 | | | | ads 2 |
lae aar $2==2 && rom(1,3)==1 && rom(1,1)!=0 | | | | adp 0-rom(1,1) ads 2 |
lae aar $2==2 && rom(1,3)==2 && rom(1,1)==0 | X_ADDREG |
			"sal %[1],1"
			erase(%[1])	   | %[1] | ads 2 |
lae aar $2==2 && rom(1,3)==2 && rom(1,1)!=0 | X_ADDREG |
			"sal %[1],1"
			erase(%[1])	   | %[1] | adp 0-2*rom(1,1) ads 2 |
lae aar $2==2 && rom(1,3)==4 && rom(1,1)==0 | X_ADDREG |
			"sal %[1],1"
			"sal %[1],1"
			erase(%[1])	   | %[1] | ads 2 |
lae aar $2==2 && rom(1,3)==4 && rom(1,1)!=0 | X_ADDREG |
			"sal %[1],1"
			"sal %[1],1"
			erase(%[1])	   | %[1] | adp 0-4*rom(1,1) ads 2 |
lae aar $2==2 && rom(1,1)==0		    | X_ACC |
			allocate(DXREG,REG={ANYCON,rom(1,3)})
			"mul %[b]"
			erase(%[1])	    | %[1] | ads 2 |
lae aar $2==2 && defined(rom(1,1))	    | X_ACC |
			allocate(DXREG,REG={ANYCON,rom(1,3)})
			"mul %[b]"
			erase(%[1])  | %[1] | adp 0-rom(1,1)*rom(1,3) ads 2 |
loc sli ads $1==1 && $2==2 && $3==2 | X_ADDREG |
			"sal %[1],1"
			erase(%[1])     | %[1] | ads 2 |
#ifdef REGVARS
...	| nocoercions: rmorconst-ADDREG uses_bx |
			allocate(%[2],REG=%[2],ADDREG=%[1])
			"sal %[b],1"
			erase(%[b])     | %[b] %[a] | ads 2 |
#endif
loc sli ads $1==2 && $2==2 && $3==2 | X_ADDREG |
			"sal %[1],1"
			"sal %[1],1"
			erase(%[1])     | %[1] | ads 2 |
#ifdef REGVARS
...	| nocoercions: rmorconst-ADDREG uses_bx |
			allocate(%[2],REG=%[2],ADDREG=%[1])
			"sal %[b],1"
			"sal %[b],1"
			erase(%[b])     | %[b] %[a] | ads 2 |
#endif
loc sli ads $2==2 && $3==2 | X_ADDREG |
			allocate(CXREG={ANYCON, $1})
			"sal %[1],cl"
			erase(%[1])     | %[1] | ads 2 |
#ifdef REGVARS
...	| nocoercions: rmorconst-(ADDREG+CXREG) uses_bx |
			allocate(%[2],REG=%[2],ADDREG=%[1],CXREG={ANYCON,$1})
			"sal %[b],cl"
			erase(%[b])     | %[b] %[a] | ads 2 |
#endif
aar $1==2	 | halfindir X_ACC X_ADDREG |
			allocate(DXREG)
			"sub %[2],%[1]"
			"mul 4+%[1]"
			"add %[3],%[2]"
			erase(%[2]) erase(%[3])
					    | %[3] | |
...		| ADDR_EXTERN X_ACC X_ADDREG |
			allocate(DXREG)
			"sub %[2],(%[1])"
			"mul (4+%[1])"
			"add %[3],%[2]"
			erase(%[2]) erase(%[3])
					    | %[3] | |
lae sar defined(rom(1,3)) | |	|	| lae $1 aar $2 sti rom(1,3) |
lae lar defined(rom(1,3)) | |	|	| lae $1 aar $2 loi rom(1,3) |
aar !defined($1) | |	remove(ALL)
			"call .iaar"	    | bx | |
sar $1==2	| X_BXREG X_ACC |
			remove(ALL)
			"call .sar2"
			erase(%[1]) erase(%[2])
						 | | |
sar !defined($1) | |	remove(ALL)
			"call .isar"	       | | |
lar $1==2	| X_BXREG X_ACC |
			remove(ALL)
			"call .lar2"
			erase(%[1]) erase(%[2])
						 | | |
lar !defined($1) | |	remove(ALL)
			"call .ilar"	       | | |

/****************************************
 * group 12 : Compare instructions	*
 ****************************************/

cmi $1==2	| NO register rmorconst |
			allocate(REG = {ANYCON,0})
			"cmp %[1],%[2]"
			"je 2f"
			"jl 1f"
			"inc %[a]"
			"jmp 2f"
			"1:\tdec %[a]\n2:"
			setcc(%[a])
			erase(%[a])		     | %[a] | |(4,4)
...	       | rmorconst register |
			allocate(REG = {ANYCON,0})
			"cmp %[1],%[2]"
			"je 2f"
			"jl 1f"
			"inc %[a]"
			"jmp 2f"
			"1:\tdec %[a]\n2:"
			setcc(%[a])
			erase(%[a])		     | %[a] | |(4,4)
...	       | ACC const |
			allocate(REG = {ANYCON,0})
			"cmp %[1],%[2]"
			"je 2f"
			"jl 1f"
			"inc %[a]"
			"jmp 2f"
			"1:\tdec %[a]\n2:"
			setcc(%[a])
			erase(%[a])		     | %[a] | |(3,4)
...	       | const ACC |
			allocate(REG = {ANYCON,0})
			"cmp %[1],%[2]"
			"je 2f"
			"jl 1f"
			"inc %[a]"
			"jmp 2f"
			"1:\tdec %[a]\n2:"
			setcc(%[a])
			erase(%[a])		     | %[a] | |(3,4)
cmi $1==4	| |	remove(ALL)
			"call .cmi4"			| ax | |
cmu $1==2	| |	|				    | cmp |
cmu $1==4	| |	remove(ALL)
			"call .cmu4"		       | ax | |
cms $1==2	| NO X_REG rmorconst |
			"sub %[1],%[2]"
			erase(%[1]) setcc(%[1]) |      %[1] | | (2,3) + %[2]
...		| rmorconst X_REG |
			"sub %[2],%[1]"
			erase(%[2]) setcc(%[2]) |      %[2] | | (2,3) + %[1]
...		| X_ACC const |
			"sub %[1],%[2]"
			erase(%[1]) setcc(%[1]) |      %[1] | | (3,4)
...		| const X_ACC |
			"sub %[2],%[1]"
			erase(%[2]) setcc(%[2]) |      %[2] | | (3,4)
cms $1==4	| rmorconst rmorconst X_REG X_REG |
			"sub %[3],%[1]"
			"sbb %[4],%[2]"
			"or %[4],%[3]"
			setcc(%[4]) erase(%[3]) erase(%[4])
						     | %[4] | |
...		| NO X_REG X_REG rmorconst rmorconst |
			"sub %[1],%[3]"
			"sbb %[2],%[4]"
			"or %[2],%[1]"
			setcc(%[2]) erase(%[1]) erase(%[2])
						     | %[2] | |
cms defined($1) | |	remove(ALL)
			move({ANYCON,$1},cx)
			"call .cms"
			erase(cx)		       | cx | |
cms !defined($1)| X_CXREG |
			remove(ALL)
			"call .cms"
			erase(cx)		       | cx | |

/*
 * Floating point
 * Comparision
 */

cmf $1==4	| | remove(ALL) | | cal ".cmf4" asp 8 lfr 2 |
cmf $1==8	| | remove(ALL) | | cal ".cmf8" asp 16 lfr 2 |
/*
 * Floating Point
 * Zero Constants
 */
zrf		| | | | zer $1 |

/* The costs with cmp are the cost of the 8086 cmp instruction */
cmp		| NO register rmorconst |
			allocate(REG = {ANYCON,0})
			"cmp %[1],%[2]"
			"je 2f"
			"jb 1f"
			"inc %[a]"
			"jmp 2f"
			"1:\tdec %[a]\n2:"
			setcc(%[a])
			erase(%[a])		     | %[a] | |(4,4)
...	       | rmorconst register |
			allocate(REG = {ANYCON,0})
			"cmp %[1],%[2]"
			"je 2f"
			"jb 1f"
			"inc %[a]"
			"jmp 2f"
			"1:\tdec %[a]\n2:"
			setcc(%[a])
			erase(%[a])		     | %[a] | |(4,4)
...	       | ACC const |
			allocate(REG = {ANYCON,0})
			"cmp %[1],%[2]"
			"je 2f"
			"jb 1f"
			"inc %[a]"
			"jmp 2f"
			"1:\tdec %[a]\n2:"
			setcc(%[a])
			erase(%[a])		     | %[a] | |(3,4)
...	       | const ACC |
			allocate(REG = {ANYCON,0})
			"cmp %[1],%[2]"
			"je 2f"
			"jb 1f"
			"inc %[a]"
			"jmp 2f"
			"1:\tdec %[a]\n2:"
			setcc(%[a])
			erase(%[a])		     | %[a] | |(3,4)
tlt		| rm |
			allocate(REG={ANYCON,0})
			test(%[1])
			"jge 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
tle		| rm |
			allocate(REG={ANYCON,0})
			test(%[1])
			"jg 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
teq		| rm |
			allocate(REG={ANYCON,0})
			test(%[1])
			"jne 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
tne		| rm |
			allocate(REG={ANYCON,0})
			test(%[1])
			"je 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
tge		| rm |
			allocate(REG={ANYCON,0})
			test(%[1])
			"jl 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
tgt		| rm |
			allocate(REG={ANYCON,0})
			test(%[1])
			"jle 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
tlt ior $2==2	| rm X_REG |
			test(%[1])
			"jge 1f"
			"or %[2],1\n1:"
			erase(%[2])		     | %[2] | |
tle ior $2==2	| rm X_REG |
			test(%[1])
			"jg 1f"
			"or %[2],1\n1:"
			erase(%[2])		     | %[2] | |
teq ior $2==2	| rm X_REG |
			test(%[1])
			"jne 1f"
			"or %[2],1\n1:"
			erase(%[2])		     | %[2] | |
tne ior $2==2	| rm X_REG |
			test(%[1])
			"je 1f"
			"or %[2],1\n1:"
			erase(%[2])		     | %[2] | |
tge ior $2==2	| rm X_REG |
			test(%[1])
			"jl 1f"
			"or %[2],1\n1:"
			erase(%[2])		     | %[2] | |
tgt ior $2==2	| rm X_REG |
			test(%[1])
			"jle 1f"
			"or %[2],1\n1:"
			erase(%[2])		     | %[2] | |
cmi tlt ior $1==2 && $3==2	| regorconst rm X_REG |
			"cmp %[2],%[1]"
			"jge 1f"
			"or %[3],1\n1:"
			erase(%[3])		     | %[3] | |
cmi tle ior $1==2 && $3==2	| regorconst rm X_REG |
			"cmp %[2],%[1]"
			"jg 1f"
			"or %[3],1\n1:"
			erase(%[3])		     | %[3] | |
cmi teq ior $1==2 && $3==2	| regorconst rm X_REG |
			"cmp %[2],%[1]"
			"jne 1f"
			"or %[3],1\n1:"
			erase(%[3])		     | %[3] | |
cmi tne ior $1==2 && $3==2	| regorconst rm X_REG |
			"cmp %[2],%[1]"
			"je 1f"
			"or %[3],1\n1:"
			erase(%[3])		     | %[3] | |
cmi tge ior $1==2 && $3==2	| regorconst rm X_REG |
			"cmp %[2],%[1]"
			"jl 1f"
			"or %[3],1\n1:"
			erase(%[3])		     | %[3] | |
cmi tgt ior $1==2 && $3==2	| regorconst rm X_REG |
			"cmp %[2],%[1]"
			"jle 1f"
			"or %[3],1\n1:"
			erase(%[3])		     | %[3] | |
/* The cmp instruction has a special form for comparing
   a byte ( sign-extended ) to a word (e.g. a register)
   The "cmp ax,0" and "cmp bx,0" instructions have widely different
   encodings but take the same amount of time and space.
   Conclusion, using the special instruction for comparing
   constants with ax is only better when the constant is <-128 or >127.
   This relatively rare event wasn't worth extra entries in this table.
*/
cmi tlt $1==2	| regorconst rm |
			allocate(REG={ANYCON,0})
			"cmp %[2],%[1]"
			"jge 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
...		| NO rm regorconst |
			allocate(REG={ANYCON,0})
			"cmp %[1],%[2]"
			"jle 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
cmi tle $1==2	| regorconst rm |
			allocate(REG={ANYCON,0})
			"cmp %[2],%[1]"
			"jg 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
...		| NO rm regorconst |
			allocate(REG={ANYCON,0})
			"cmp %[1],%[2]"
			"jl 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
cmi teq $1==2	| regorconst rm |
			allocate(REG={ANYCON,0})
			"cmp %[2],%[1]"
			"jne 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
...		| NO rm regorconst |
			allocate(REG={ANYCON,0})
			"cmp %[1],%[2]"
			"jne 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
cmi tne $1==2	| regorconst rm |
			allocate(REG={ANYCON,0})
			"cmp %[2],%[1]"
			"je 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
...		| NO rm regorconst |
			allocate(REG={ANYCON,0})
			"cmp %[1],%[2]"
			"je 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
cmi tge $1==2	| regorconst rm |
			allocate(REG={ANYCON,0})
			"cmp %[2],%[1]"
			"jl 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
...		| NO rm regorconst |
			allocate(REG={ANYCON,0})
			"cmp %[1],%[2]"
			"jg 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
cmi tgt $1==2	| regorconst rm |
			allocate(REG={ANYCON,0})
			"cmp %[2],%[1]"
			"jle 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
...		| NO rm regorconst |
			allocate(REG={ANYCON,0})
			"cmp %[1],%[2]"
			"jge 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
cmp tlt 	| regorconst rm |
			allocate(REG={ANYCON,0})
			"cmp %[2],%[1]"
			"jae 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
...		| NO rm regorconst |
			allocate(REG={ANYCON,0})
			"cmp %[1],%[2]"
			"jbe 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
cmp tle 	| regorconst rm |
			allocate(REG={ANYCON,0})
			"cmp %[2],%[1]"
			"ja 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
...		| NO rm regorconst |
			allocate(REG={ANYCON,0})
			"cmp %[1],%[2]"
			"jb 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
cmp teq 	| regorconst rm |
			allocate(REG={ANYCON,0})
			"cmp %[2],%[1]"
			"jne 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
...		| NO rm regorconst |
			allocate(REG={ANYCON,0})
			"cmp %[1],%[2]"
			"jne 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
cmp tne 	| regorconst rm |
			allocate(REG={ANYCON,0})
			"cmp %[2],%[1]"
			"je 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
...		| NO rm regorconst |
			allocate(REG={ANYCON,0})
			"cmp %[1],%[2]"
			"je 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
cmp tge 	| regorconst rm |
			allocate(REG={ANYCON,0})
			"cmp %[2],%[1]"
			"jb 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
...		| NO rm regorconst |
			allocate(REG={ANYCON,0})
			"cmp %[1],%[2]"
			"ja 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
cmp tgt 	| regorconst rm |
			allocate(REG={ANYCON,0})
			"cmp %[2],%[1]"
			"jbe 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
...		| NO rm regorconst |
			allocate(REG={ANYCON,0})
			"cmp %[1],%[2]"
			"jae 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
cms teq $1==2	| regorconst rm |
			allocate(REG={ANYCON,0})
			"cmp %[2],%[1]"
			"jne 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
...		| NO rm regorconst |
			allocate(REG={ANYCON,0})
			"cmp %[1],%[2]"
			"jne 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
cms tne $1==2	| regorconst rm |
			allocate(REG={ANYCON,0})
			"cmp %[2],%[1]"
			"je 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
...		| NO rm regorconst |
			allocate(REG={ANYCON,0})
			"cmp %[1],%[2]"
			"je 1f"
			"inc %[a]\n1:"
			erase(%[a])		     | %[a] | |
cmp zlt 	| regorconst rm STACK |
			"cmp %[2],%[1]"
			"jb $2" 			  | | |
...		| NO rm regorconst |
			remove(ALL)
			"cmp %[1],%[2]"
			"ja $2" 			  | | |
cmp zle 	| regorconst rm STACK |
			"cmp %[2],%[1]"
			"jbe $2"			  | | |
...		| NO rm regorconst |
			remove(ALL)
			"cmp %[1],%[2]"
			"jae $2"			  | | |
cmp zeq 	| regorconst rm STACK |
			"cmp %[2],%[1]"
			"je $2" 			  | | |
...		| NO rm regorconst |
			remove(ALL)
			"cmp %[1],%[2]"
			"je $2" 			  | | |
cmp zne 	| regorconst rm STACK |
			"cmp %[2],%[1]"
			"jne $2"			  | | |
...		| NO rm regorconst |
			remove(ALL)
			"cmp %[1],%[2]"
			"jne $2"			  | | |
cmp zge 	| regorconst rm STACK |
			"cmp %[2],%[1]"
			"jae $2"			  | | |
...		| NO rm regorconst |
			remove(ALL)
			"cmp %[1],%[2]"
			"jbe $2"			  | | |
cmp zgt 	| regorconst rm STACK |
			"cmp %[2],%[1]"
			"ja $2" 			  | | |
...		| NO rm regorconst |
			remove(ALL)
			"cmp %[1],%[2]"
			"jb $2" 			  | | |
cms zeq $1==2	| regorconst rm STACK |
			"cmp %[2],%[1]"
			"je $2"			  	  | | |
...		| NO rm regorconst |
			remove(ALL)
			"cmp %[1],%[2]"
			"je $2"			  	  | | |
cms zne $1==2	| regorconst rm STACK |
			"cmp %[2],%[1]"
			"jne $2" 			  | | |
...		| NO rm regorconst |
			remove(ALL)
			"cmp %[1],%[2]"
			"jne $2" 			  | | |
ldc cmi zlt highw(1)==0 && loww(1)==0 && $2==4 | rmorconst rmorconst |
                                        | %[2] | zlt $3 |
ldc cmi zge highw(1)==0 && loww(1)==0 && $2==4 | rmorconst rmorconst |
                                        | %[2] | zge $3 |
ldc cms zeq $2==4 && loww(1)==0 && highw(1)==0 | rmorconst X_REG |
                        remove(ALL)
                        "or %[2],%[1]"
                        "je $3"                        |               | |
...						| X_REG rmorconst |
			remove(ALL)
			"or %[1],%[2]"
			"je $3"			|		| |
ldc cms zne $2==4 && loww(1)==0 && highw(1)==0 | rmorconst X_REG |
                        remove(ALL)
                        "or %[2],%[1]"
                        "jne $3"                        |               | |
...						| X_REG rmorconst |
			remove(ALL)
			"or %[1],%[2]"
			"jne $3"			|		| |
ldc cms zeq $2==4       | rmorconst rmorconst |
                        remove(ALL)
                        "cmp %[1],%(loww(1)%)"
                        "jne 1f"
                        "cmp %[2],%(highw(1)%)"
                        "je $3"
                        "1:"                            |               | |
ldc cms zne $2==4       | rmorconst rmorconst |
                        remove(ALL)
                        "cmp %[1],%(loww(1)%)"
                        "jne $3"
                        "cmp %[2],%(highw(1)%)"
                        "jne $3"                        |               | |
cms zne $1==4	| regorconst regorconst rm rm STACK |
			"cmp %[3],%[1]"
			"jne $2"
			"cmp %[4],%[2]"
			"jne $2"			  | | |
...		| NO rm rm regorconst regorconst |
			remove(ALL)
			"cmp %[1],%[3]"
			"jne $2"
			"cmp %[2],%[4]"
			"jne $2"			  | | |
cms zeq $1==4	| regorconst regorconst rm rm STACK |
			"cmp %[3],%[1]"
			"jne 1f"
			"cmp %[4],%[2]"
			"je $2\n1:"			  | | |
...		| NO rm rm regorconst regorconst |
			remove(ALL)
			"cmp %[1],%[3]"
			"jne 1f"
			"cmp %[2],%[4]"
			"je $2\n1:"			  | | |
and zeq $1==2	| regorconst rm STACK |
			"test %[2],%[1]"
			"je $2" 			  | | |
...		| NO rm regorconst |
			remove(ALL)
			"test %[1],%[2]"
			"je $2"				  | | |
and zne $1==2	| regorconst rm STACK |
			"test %[2],%[1]"
			"jne $2" 			  | | |
...		| NO rm regorconst |
			remove(ALL)
			"test %[1],%[2]"
			"jne $2"			  | | |
loc and zeq $1<256 && $1>=0 && $2==2	| nocoercions : rm1 + memory2 |
			remove(ALL)
			"testb %[1],$1"
			"je $3" 			  | | | (1,3) + %[1]
...						| GENREG STACK |
			"testb %[1.1],$1"
			"je $3" 			  | | | (1,3) + %[1]
...						| nocoercions : IREG |
			remove(ALL)
			"test %[1],$1"
			"je $3" 			  | | | (2,3) + %[1]
loc and zne $1<256 && $1>=0 && $2==2		| nocoercions : rm1 + memory2 |
			remove(ALL)
			"testb %[1],$1"
			"jne $3" 			  | | | (1,3) + %[1]
...						| GENREG STACK |
			"testb %[1.1],$1"
			"jne $3" 			  | | | (1,3) + %[1]
...						| nocoercions : IREG |
			remove(ALL)
			"test %[1],$1"
			"jne $3" 			  | | | (2,3) + %[1]
loc beq $1<256 && $1>=0		 		| nocoercions : rm1 |
			remove(ALL)
			"cmpb %[1],$1"
			"je $2" 			  | | | (1,3) + %[1]
...						| rm STACK |
			"cmp %[1],$1"
			"je $2" 			  | | | (2,3) + %[1]
loc bne $1<256 && $1>=0		 		| nocoercions : rm1 |
			remove(ALL)
			"cmpb %[1],$1"
			"jne $2" 			  | | | (1,3) + %[1]
...						| rm STACK |
			"cmp %[1],$1"
			"jne $2" 			  | | | (2,3) + %[1]
/* Note: test for <,<=,>,>= can be done in this way,
	 with use of the unsigned conditional jumps, jb, etc. */
loc cmu zeq $1<256 && $1>=0 && $2==2		| nocoercions : rm1 |
			remove(ALL)
			"cmpb %[1],$1"
			"je $3" 			  | | | (1,3) + %[1]
...						| rm STACK |
			"cmp %[1],$1"
			"je $3" 			  | | | (2,3) + %[1]
loc cmu zne $1<256 && $1>=0 && $2==2		| nocoercions : rm1 |
			remove(ALL)
			"cmpb %[1],$1"
			"jne $3" 			  | | | (1,3) + %[1]
...						| rm STACK |
			"cmp %[1],$1"
			"jne $3" 			  | | | (2,3) + %[1]

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

bra		| |	remove(ALL)
			"jmp $1"
			samecc				  | | |
blt		| regorconst rm STACK |
			"cmp %[2],%[1]"
			"jl $1" 			  | | |
...		| NO rm regorconst |
			remove(ALL)
			"cmp %[1],%[2]"
			"jg $1" 			  | | |
ble		| regorconst rm STACK |
			"cmp %[2],%[1]"
			"jle $1"			  | | |
...		| NO rm regorconst |
			remove(ALL)
			"cmp %[1],%[2]"
			"jge $1"			  | | |
beq		| regorconst rm STACK |
			"cmp %[2],%[1]"
			"je $1" 			  | | |
...		| NO rm regorconst |
			remove(ALL)
			"cmp %[1],%[2]"
			"je $1" 			  | | |
bne		| regorconst rm STACK |
			"cmp %[2],%[1]"
			"jne $1"			  | | |
...		| NO rm regorconst |
			remove(ALL)
			"cmp %[1],%[2]"
			"jne $1"			  | | |
bge		| regorconst rm STACK |
			"cmp %[2],%[1]"
			"jge $1"			  | | |
...		| NO rm regorconst |
			remove(ALL)
			"cmp %[1],%[2]"
			"jle $1"			  | | |
bgt		| regorconst rm STACK |
			"cmp %[2],%[1]"
			"jg $1" 			  | | |
...		| NO rm regorconst |
			remove(ALL)
			"cmp %[1],%[2]"
			"jl $1" 			  | | |
zlt		| rm STACK |
			test(%[1])
			"jl $1" 			  | | |
zle		| rm STACK |
			test(%[1])
			"jle $1"			  | | |
zeq		| rm+rm1 STACK |
			test(%[1])
			"je $1" 			  | | |
zne		| rm+rm1 STACK |
			test(%[1])
			"jne $1"			  | | |
zge		| rm STACK |
			test(%[1])
			"jge $1"			  | | |
zgt		| rm STACK |
			test(%[1])
			"jg $1" 			  | | |

/************************************************
 * group 14 : Procedure call instructions	*
 ************************************************/

cal		| |	remove(ALL)
			"call $1"			  | | |
cai		| rm |	remove(ALL)
			"call %[1]"			  | | |
lfr $1==2	| |				       | ax | |
lfr $1==4	| |				    | dx ax | |
lfr $1==6	| | 	remove(ALL)
			"call .lfr6"			  | | |
lfr $1==8	| |	remove(ALL)
			"call .lfr8"			  | | |
ret $1==0	| |	remove(ALL)
#ifdef REGVARS
			return
#else
			"mov sp,bp"
			"pop bp"
			"ret"				 
#endif
							| | |
ret $1==2	| ACC |
			remove(ALL)
#ifdef REGVARS
			return
#else
			"mov sp,bp"
			"pop bp"
			"ret"
#endif
							| | |
ret $1==4	| ACC DXREG |
			remove(ALL)
#ifdef REGVARS
			return
#else
			"mov sp,bp"
			"pop bp"
			"ret"
#endif
							| | |
ret $1==6	| STACK |
			"call .ret6"
#ifdef REGVARS
			return
#else
			"mov sp,bp"
			"pop bp"
			"ret"
#endif
							| | |
ret $1==8	| STACK |
			"call .ret8"
#ifdef REGVARS
			return
#else
			"mov sp,bp"
			"pop bp"
			"ret"
#endif
							| | |

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

asp $1==2	| nocoercions : a_word |		  | | |
...		| STACK |
			allocate(BXREG)
			"pop %[a]" erase(%[a]) samecc	  | | | (1,8)
asp $1==4	| nocoercions : a_word a_word | 	  | | |
...		| STACK |
			allocate(BXREG)
			"pop %[a]" "pop %[a]"
			erase(%[a]) samecc		  | | | (2,16)
asp $1==0-2	| |	/* Anything will do */	       | bp | |
asp		| STACK |
			"add sp,$1"			  | | | (4,4)
ass $1==2	| rmorconst STACK |
			"add sp,%[1]"			  | | |
ass !defined($1)| rm rmorconst STACK |
			"cmp %[1],2"
			"jne .unknown"
			"add sp,%[2]"			  | | |
blm $1==0	| |					  | | asp 4 |
blm $1>0	| |
			remove(ALL)
			allocate(CXREG={ANYCON,$1/2})
			"call .blm"
			erase(%[a])
							  | | |
bls $1==2	| X_CXREG |
			remove(ALL)
			"sar cx,1"
			"call .blm"
			erase(%[1])
							  | | |
bls !defined($1)| rm-CXREG X_CXREG |
			remove(ALL)
			"cmp %[1],2"
			"jne .unknown"
			"sar cx,1"
			"call .blm"
			erase(%[2])
							  | | |
csa $1==2	| X_BXREG X_ACC |
			remove(ALL)
			"jmp .csa2"
			erase(%[1]) erase(%[2]) 	  | | |
csa !defined($1)| rm-BXREG-ACC X_BXREG X_ACC |
			remove(ALL)
			"cmp %[1],2"
			"jne .unknown"
			"jmp .csa2"
			erase(%[2]) erase(%[3]) 	  | | |
csb $1==2	| X_BXREG X_ACC |
			remove(ALL)
			"jmp .csb2"
			erase(%[1]) erase(%[2]) 	  | | |
csb !defined($1)| rm-BXREG-ACC X_BXREG X_ACC |
			remove(ALL)
			"cmp %[1],2"
			"jne .unknown"
			"jmp .csb2"
			erase(%[2]) erase(%[3]) 	  | | |
dup $1==2	| regorconst |				| %[1] %[1] | |
...		| ACC1 |			| %[1] %[1] | |
dup $1==4	| regorconst regorconst |	      | %[2] %[1] %[2] %[1] | |
dup		| |	remove(ALL)
			move({ANYCON, $1}, cx)
			"call .dup"
			erase(cx)			  | | |
dus $1==2	| X_CXREG |
			remove(ALL)
			"call .dup"
			erase(%[1])			  | | |
dus !defined($1)| rm-CXREG X_CXREG |
			remove(ALL)
			"cmp %[1],2"
			"jne .unknown"
			"call .dup"
			erase(%[2])			  | | |
exg $1==2	| a_word a_word |		| %[1] %[2] | |
exg $1==4	| a_word a_word a_word a_word |
				      | %[2] %[1] %[4] %[3] | |
exg defined($1) | |	remove(ALL)
			move({ANYCON,$1},cx)
			"call .exg"
			erase(cx)			  | | |
exg		| rmorconst |
			remove(ALL)
			move(%[1],cx)
			"call .exg"
			erase(cx)			  | | |
gto		| |	remove(ALL)
			"mov bx,$1"
			"jmp .gto"			  | | |
fil		| |	"mov (hol0+4),$1"		  | | |
lim		| |	allocate(REG)
			"mov %[a],(.ignmask)"	     | %[a] | |
lin		| |	"mov (hol0),$1" 		  | | |
lni		| |	"inc (hol0)"			  | | |
lor $1==0	| |				       | bp | |
lor $1==1	| STACK |
			allocate(REG)
			"mov %[a],sp"		     | %[a] | |
lor $1==2	| |	allocate(REG)
			"mov %[a],(.reghp)"	     | %[a] | |
mon		| X_ACC |
			remove(ALL)
			"call .mon"			  | | |
nop		| |	remove(ALL)
			"call .nop"			  | | |
rck $1==2	| BXREG ACC |
			"call .rck"		       | ax | |
rck !defined($1)| rm-BXREG-ACC BXREG ACC |
			"cmp %[1],2"
			"jne .unknown"
			"call .rck"		       | ax | |
rtt		| |		|			    | ret 0 |
sig		| X_REG |
			"xchg (.trppc),%[1]"
			erase(%[1])		     | %[1] | |
sim		| regorconst |
			"mov (.ignmask),%[1]"		  | | |
str $1==0	| rmorconst |
			"mov bp,%[1]"			  | | |
str $1==1	| rmorconst STACK |
			"mov sp,%[1]"			  | | |
str $1==2	| |
			remove(ALL)
			"call .strhp"			  | | |
trp		| X_ACC |
			remove(ALL)
			"call .Xtrp"			  | | |

/********************************
 * From source to register	*
 ********************************/

| rmorconst  |	allocate(%[1],REG=%[1]) 	| %[a]	| |
| Xreg_off |	"add %[1.reg],%[1.off]"
		erase(%[1.reg]) setcc(%[1.reg]) 
					    | %[1.reg]  | |(2,3) + %[1]
| halfindir |
		allocate(%[1],REG)
		move(%[1],%[a])
		samecc				| %[a]	| |(0,0)
| halfindir |
		allocate(%[1],ADDREG)
		move(%[1],%[a])
		samecc				| %[a]	| |(0,0)

/********************************
 * From source to token 	*
 ********************************/

| ANYCON     |	     | {ADDR_EXTERN,tostring(%[1.val])} | |

/********************************
 * From source1 		*
 ********************************/

| rm1 | 	allocate(%[1],REG1=%[1])	| %[a]	| |
| rm1 | 	allocate(%[1],GENREG)
		move(%[1],%[a.1])
		"xorb %[a.2],%[a.2]"		| %[a]	| |(2,3)
| ACC1 |	allocate(%[1],ACC)
		"xorb %[a.2],%[a.2]"		| %[a]	| |(2,3)
/*
| BLREG |	allocate(%[1],BXREG)
		"xorb %[a.2],%[a.2]"		| %[a]	| |(2,3)
*/



/************************
 * From STACK coercions *
 ************************/

| STACK |	allocate(REG)
		"pop %[a]"
		samecc				| %[a]	| | (2,8)

MOVES:
(ACC,		   EXTERN2,   "mov %[2],%[1]" samecc,	   (3,16))
(ACC1,		   EXTERN1,   "movb %[2],%[1]" samecc,	   (3,16))
(ACC,		   EXTERN1,   "movb %[2],%[1.1]" samecc,   (3,16))
(EXTERN2,	   ACC,       "mov %[2],%[1]" samecc,	   (3,14))
(EXTERN1,	   ACC1,      "movb %[2],%[1]" samecc,	   (3,14))
(rm,		   register,  "mov %[2],%[1]" samecc,	   (2,2) + %[1] )
(anyreg,	   dest,      "mov %[2],%[1]" samecc,	   (2,3) + %[2] )
(halfindir,	   register,  "lea %[2],%[1]" samecc,	   (2,3) + %[1] )
(rm1,		   REG1,      "movb %[2],%[1]" samecc,	   (2,2) + %[1] )
(REG1,		   rm1,       "movb %[2],%[1]" samecc,	   (2,3) + %[2] )
(GENREG,	   rm1,       "movb %[2],%[1.1]" samecc,   (2,3) + %[2] )
(ANYCON %[val]==0, register,  "xor %[2],%[2]" setcc(%[2]), (2,3))
(ANYCON %[val]==0, REG1,      "xorb %[2],%[2]" setcc(%[2]),(2,3))
(const, 	   register,  "mov %[2],%[1]" samecc,	   (3,4))
(const, 	   REG1,      "movb %[2],%[1]" samecc,	   (2,4))
(const, 	   dest,      "mov %[2],%[1]" samecc,	   (4,4) + %[2] )
(const, 	   rm1,       "movb %[2],%[1]" samecc,	   (3,4) + %[2] )

TESTS:
(anyreg,	"or %[1],%[1]", 	(2,3))
(memory2,	"cmp %[1],0",		(3,11)+%[1])
(REG1,		"orb %[1],%[1]", 	(2,3))
(memory1,	"cmpb %[1],0",		(3,11)+%[1])

STACKS:
(anyreg, ,	"push %[1]"
		samecc			      ,  (1,10) )
(memory2, ,	"push %[1]"
		samecc			      ,  (2,10) + %[1] )
(const, REG,	move(%[1],%[a])
		"push %[a]"
		samecc			      ,  (4,11) )
(const, ,	".sect .data\n1: .data2 %[1]\n.sect .text"
		"push (1b)"
		samecc			      ,  (6,24) )
(rm1, GENREG,	move({ANYCON,0},%[a])
		move(%[1],%[a.1])
		"push %[a]"
		samecc			      ,  (2,10) + %[1] )
(rm1, , 	"push %[1]"
		"push si"
		"mov si,sp"
		"movb 3(si),0"
		"pop si"
		samecc			      ,  (10,60) + %[1] )
(Xreg_off, ,	"add %[1.reg],%[1.off]"
		"push %[1.reg]"
		erase(%[1.reg])
		setcc(%[1.reg])		      ,  ( 4,14) )
(Xbpreg_off, ,	move(%[1],%[1.reg])
		"push %[1.reg]"
		samecc			      ,  ( 6,17) + %[1] )
(ADDR_LOCAL %[ind]==0 , ,
		"push bp"
		samecc			      ,  ( 1, 10) )
(halfindir, REG,move(%[1],%[a])
		"push %[a]"
		samecc			      ,  ( 6,17) + %[1] )
(halfindir, ,	"push ax"
		"push si"
		"lea ax,%[1]"
		"mov si,sp"
		"xchg 2(si),ax"
		"pop si"
		samecc			      ,  (10,59) + %[1] )
