--- /dev/null
+/*
+ * (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"
+
+/********************************************************
+ * Back end tables for Intel 8086 *
+ * Author : Ed Keizer *
+ * *
+ * 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.
+bx = ("bx", 2, bl, bh), REG, GENREG, BREG, BXREG, ADDREG.
+cx = ("cx", 2, cl, ch), REG, GENREG, CXREG, SHIFT_CREG.
+dx = ("dx", 2, dl, dh), REG, GENREG, DXREG.
+si = ("si", 2), REG, IREG, SIREG, ADDREG.
+di = ("di", 2), REG, IREG, DIREG, ADDREG.
+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) *
+ *****************************************/
+
+reg_off = { REGISTER reg; STRING off; } 2 cost=(1, 9) "%[off](%[reg])"
+bpreg_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
+X_SIREG = SIREG*SCRATCH
+X_DIREG = DIREG*SCRATCH
+X_ADDREG = ADDREG*SCRATCH
+
+/* 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
+anyreg = REG + BREG
+rm = anyreg + memory2
+rmorconst = const + rm
+regorconst = const + anyreg
+dest = REG + 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 */
+halfindir = reg_off + bpreg_off + ADDR_LOCAL
+some_off = halfindir + ADDR_EXTERN + ADDREG
+a_word = rmorconst + rm1 + halfindir
+no_reg_off = rmorconst + rm1 + ADDR_LOCAL
+
+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)} | |
+lol | | | {LOCAL2, $1, 2} | |
+loe | | | {EXTERN2, $1} | |
+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 })
+ | {reg_off, %[a], SSL } | |
+lxa $1==2 | | allocate(ADDREG={ind_regoff2, bp, SSL })
+ move({ind_regoff2, %[a], SSL }, %[a])
+ | {reg_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])
+ | {reg_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 | X_SIREG |
+ remove(ALL)
+ allocate(CXREG={ANYCON,$1})
+ "sub sp,cx"
+ "sar cx,1"
+ "mov di,sp"
+ "rep movs"
+ erase(%[a]) erase(%[1]) | | | (8,8+$1*9)
+... | X_SIREG |
+ remove(ALL)
+ allocate(CXREG={ANYCON,$1})
+ "call .loi"
+ erase(%[a]) erase(%[1]) | | | (3,32+$1*9)
+los $1==2 | X_CXREG X_SIREG |
+ remove(ALL)
+ "call .loi"
+ erase(%[1]) erase(%[2]) | | |
+los !defined($1)| rm X_CXREG X_SIREG |
+ remove(ALL)
+ "cmp %[1],2"
+ "jne .unknown"
+ "call .loi"
+ 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. *
+ ****************************************************************/
+
+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 | | |
+sil | regorconst |
+ allocate(ADDREG={ind_regoff2, bp, tostring($1)})
+ remove(referals)
+ move(%[1], {ind_reg2, %[a]}) | | |
+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 | | |
+... | 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 | | |
+... | 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],{ind_regoff1, bp, tostring(%[1.ind])})
+ | | |
+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 | X_DIREG |
+ remove(ALL)
+ allocate(CXREG={ANYCON,$1/2})
+ "mov si,sp"
+ "rep movs"
+ "mov sp,si"
+ erase(%[1]) erase(%[a]) | | | (5,4+$1*8)
+/* 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_DIREG |
+ remove(ALL)
+ "call .sti"
+ erase(%[1]) erase(%[2]) | | |
+sdl | | | | stl $1 stl $1+2 |
+sde | | | | 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 */
+... | 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]
+... | 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]
+... | 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]
+... | 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]
+... | rm-ACC X_ACC |
+ allocate(%[1],DXREG)
+ "mul %[1]"
+ nocc erase(%[2]) | %[2] | |(2,118)+%[1]
+mli $1==4 | SIREG DIREG BXREG X_ACC |
+ remove(ALL)
+ "call .mli4"
+ erase(ax) setcc(dx) | dx ax | |
+/* Not now,
+mli !defined($1)| X_ACC |
+ remove(ALL)
+ "call .mli" | | |
+*/
+dvi $1==2 | rm-ACC X_ACC |
+ allocate(DXREG)
+ "cwd"
+ "idiv %[1]"
+ erase(%[2]) | ax | |(3,176)+%[1]
+dvi $1==4 | | remove(ALL)
+ "call .dvi4" | cx ax | |
+/*
+dvi !defined($1)| X_ACC |
+ remove(ALL)
+ "call .dvi" erase(%[1]) | | |
+*/
+#ifdef LONGEMPAT
+loc loc cii dvi loc loc cii $1==2 && $2==4 && $4==4 && $5==4 && $6==2
+ | rm-ACC-DXREG X_ACC X_DXREG |
+ "idiv %[1]"
+ erase(%[2]) erase(%[3]) | ax | |(2,171)+%[1]
+#endif
+rmi $1==2 | rm-ACC X_ACC |
+ allocate(DXREG)
+ "cwd"
+ "idiv %[1]"
+ erase(%[2]) | dx | |(3,176)+%[1]
+rmi $1==4 | | remove(ALL)
+ "call .rmi4" | bx dx | |
+/*
+rmi !defined($1)| X_ACC |
+ remove(ALL)
+ "call .rmi" erase(%[1]) | | |
+*/
+#ifdef LONGEMPAT
+loc loc cii rmi loc loc cii $1==2 && $2==4 && $4==4 && $5==4 && $6==2
+ | rm-ACC-DXREG X_ACC X_DXREG |
+ "idiv %[1]"
+ erase(%[2]) erase(%[3]) | dx | |(2,171)+%[1]
+#endif
+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)
+... | X_REG-ACC X_ACC |
+ "neg %[2]"
+ "neg %[1]"
+ "sbb %[2],0"
+ setcc(%[2]) erase(%[1]) erase(%[2])
+ | %[2] %[1] | | (7,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)
+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)
+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 | rm-ACC X_ACC |
+ allocate(%[1],DXREG={ANYCON,0})
+ "div %[1]"
+ erase(%[2]) erase(%[a]) | %[2] | |(2,149)+%[1]
+dvu $1==4 | | remove(ALL)
+ "call .dvu4" | cx ax | |
+/*
+dvu !defined($1)| X_ACC |
+ remove(ALL)
+ "call .dvu" erase(%[1]) | | |
+*/
+rmu $1==2 | rm-ACC X_ACC |
+ allocate(%[1],DXREG={ANYCON,0})
+ "div %[1]"
+ erase(%[2]) erase(%[a]) | dx | |(3,149)+%[1]
+rmu $1==4 | | remove(ALL)
+ "call .rmu4" | bx dx | |
+/*
+rmu !defined($1)| X_ACC |
+ remove(ALL)
+ "call .rmu" erase(%[1]) | | |
+*/
+slu | | | | sli $1 |
+loc sru $1==1 && $2==2 | X_REG |
+ "shr %[1],1"
+ setcc(%[1]) erase(%[1]) | %[1] | | (2,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 *
+ * *
+ ************************************************/
+
+adf $1==4 | |
+ remove(ALL)
+ "call .adf4" | | |
+adf $1==8 | |
+ remove(ALL)
+ "call .adf8" | | |
+adf !defined($1) | X_CXREG |
+ remove(ALL)
+ "call .adf" erase(%[1]) | | |
+sbf $1==4 | |
+ remove(ALL)
+ "call .sbf4" | | |
+sbf $1==8 | |
+ remove(ALL)
+ "call .sbf8" | | |
+sbf !defined($1) | X_CXREG |
+ remove(ALL)
+ "call .sbf" erase(%[1]) | | |
+mlf $1==4 | |
+ remove(ALL)
+ "call .mlf4" | | |
+mlf $1==8 | |
+ remove(ALL)
+ "call .mlf8" | | |
+mlf !defined($1) | X_CXREG |
+ remove(ALL)
+ "call .mlf" erase(%[1]) | | |
+dvf $1==4 | |
+ remove(ALL)
+ "call .dvf4" | | |
+dvf $1==8 | |
+ remove(ALL)
+ "call .dvf8" | | |
+dvf !defined($1) | X_CXREG |
+ remove(ALL)
+ "call .dvf" erase(%[1]) | | |
+ngf $1==4 | |
+ remove(ALL)
+ "call .ngf4" | | |
+ngf $1==8 | |
+ remove(ALL)
+ "call .ngf8" | | |
+ngf !defined($1) | X_CXREG |
+ remove(ALL)
+ "call .ngf" erase(%[1]) | | |
+fif $1==4 | |
+ remove(ALL)
+ "call .fif4" | | |
+fif $1==8 | |
+ remove(ALL)
+ "call .fif8" | | |
+fif !defined($1) | X_CXREG |
+ remove(ALL)
+ "call .fif" erase(%[1]) | | |
+fef $1==4 | |
+ remove(ALL)
+ "call .fef4" | | |
+fef $1==8 | |
+ remove(ALL)
+ "call .fef8" | | |
+fef !defined($1) | X_CXREG |
+ remove(ALL)
+ "call .fef" erase(%[1]) | | |
+
+
+
+/****************************************
+ * Group 6 : pointer arithmetic. *
+ * *
+ * Pointers have size 2 bytes. *
+ ****************************************/
+
+adp $1==1 | nocoercions : reg_off | |
+ {reg_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 : bpreg_off | |
+ {bpreg_off, %[1.reg], %[1.ind]+$1} | |
+... | X_REG |
+ "inc %[1]"
+ erase(%[1]) setcc(%[1]) | %[1] | | (1,2)
+adp $1 == 0-1 | nocoercions : reg_off | |
+ {reg_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 : bpreg_off | |
+ {bpreg_off, %[1.reg], %[1.ind]+$1} | |
+... | X_REG |
+ "dec %[1]"
+ erase(%[1]) setcc(%[1]) | %[1] | | (1,2)
+adp | nocoercions : reg_off | |
+ {reg_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 : bpreg_off | |
+ {bpreg_off, %[1.reg], %[1.ind]+$1} | |
+... | X_ADDREG | | {reg_off, %[1], tostring($1)} | |
+... | nocoercions : X_ACC + X_CXREG + X_DXREG |
+ "add %[1],$1"
+ erase(%[1]) setcc(%[1]) | %[1] | | (4,4)
+ads $1==2 | nocoercions : ANYCON reg_off | |
+ {reg_off, %[2.reg],
+ %[2.off]+"+"+tostring(%[1.val])} | |
+... | nocoercions : ADDR_EXTERN reg_off | |
+ {reg_off, %[2.reg], %[2.off]+"+"+%[1.off]} | |
+... | rm reg_off |
+ "add %[2.reg],%[1]"
+ erase(%[2.reg]) setcc(%[2.reg]) |
+ {reg_off, %[2.reg], %[2.off]} | | (2,3) + %[1]
+... | nocoercions : ANYCON bpreg_off | |
+ {bpreg_off, %[2.reg], %[2.ind]+%[1.val]} | |
+... | rm bpreg_off |
+ "add %[2.reg],%[1]"
+ erase(%[2.reg]) setcc(%[2.reg]) |
+ {bpreg_off, %[2.reg], %[2.ind]} | | (2,3) + %[1]
+... | reg_off rmorconst |
+ "add %[1.reg],%[2]"
+ erase(%[1.reg]) setcc(%[1.reg]) |
+ {reg_off, %[1.reg], %[1.off]} | | (2,3) + %[2]
+... | bpreg_off rmorconst |
+ "add %[1.reg],%[2]"
+ erase(%[1.reg]) setcc(%[1.reg]) |
+ {bpreg_off, %[1.reg], %[1.ind]} | | (2,3) + %[2]
+... | nocoercions : reg_off ANYCON | |
+ {reg_off, %[1.reg],
+ %[1.off]+"+"+tostring(%[2.val])} | |
+... | nocoercions : reg_off ADDR_EXTERN | |
+ {reg_off, %[1.reg], %[1.off]+"+"+%[2.off]} | |
+... | nocoercions : reg_off reg_off |
+ "add %[1.reg],%[2.reg]"
+ erase(%[1.reg]) setcc(%[1.reg]) |
+ {reg_off,%[1.reg],%[1.off]+"+"+%[2.off]} | | (2,3)
+... | 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)
+*/
+#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 | | {reg_off, %[1], %[2.off]} | |
+... | X_ADDREG rm |
+ "add %[1],%[2]"
+ erase(%[1]) setcc(%[1]) | %[1] | | (2,3) + %[2]
+... | ADDR_EXTERN X_ADDREG | | {reg_off, %[2], %[1.off]} | |
+... | rm X_ADDREG |
+ "add %[2],%[1]"
+ erase(%[2]) setcc(%[2]) | %[2] | | (2,3) + %[1]
+#endif
+sbs $1==2 | nocoercions : ANYCON reg_off | |
+ {reg_off, %[2.reg], %[2.off]+"-"+tostring(%[1.val])} | |
+... | nocoercions : ANYCON ADDR_LOCAL | |
+ {ADDR_LOCAL, %[2.ind]-%[1.val]} | |
+... | rm reg_off |
+ "sub %[2.reg],%[1]"
+ erase(%[2.reg]) setcc(%[2.reg]) |
+ {reg_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)
+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)
+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)
+zrl | | remove(indexed)
+ remove(locals, %[ind]>=$1 && %[ind]<$1+2 )
+ move({ANYCON,0},{LOCAL2,$1,2})
+ | | |
+zre | | remove(indirects)
+ move({ANYCON,0},{EXTERN2,$1})| | |
+zrf $1==4 | |
+ remove(ALL)
+ "call .zrf4" | | |
+zrf $1==8 | |
+ remove(ALL)
+ "call .zrf8" | | |
+zrf !defined($1) | X_CXREG |
+ remove(ALL)
+ "call .zrf" erase(%[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]) | | |
+
+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}) | | |
+lol ngi stl $1==$3 && $2==2 | |
+ remove(indexed)
+ remove(locals, %[ind]>=$1 && %[ind]<$1+2 )
+ "neg $1(bp)"
+ setcc({LOCAL2, $1, 2}) | | |
+lol ads stl $1==$3 && $2==2 | regorconst |
+ remove(indexed)
+ remove(locals, %[ind]>=$1 && %[ind]<$1+2 )
+ "add $1(bp),%[1]"
+ setcc({LOCAL2, $1, 2}) | | |
+lol adp stl $1==$3 | |
+ remove(indexed)
+ remove(locals, %[ind]>=$1 && %[ind]<$1+2 )
+ "add $1(bp),$2"
+ setcc({LOCAL2, $1, 2}) | | |
+lol adp stl $1==$3 && $2==1 | |
+ remove(indexed)
+ remove(locals, %[ind]>=$1 && %[ind]<$1+2 )
+ "inc $1(bp)"
+ setcc({LOCAL2, $1, 2}) | | |
+lol adp stl $1==$3 && $2==0-1 | |
+ remove(indexed)
+ remove(locals, %[ind]>=$1 && %[ind]<$1+2 )
+ "dec $1(bp)"
+ setcc({LOCAL2, $1, 2}) | | |
+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}) | | |
+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}) | | |
+lol com stl $1==$3 && $2==2 | |
+ remove(indexed)
+ remove(locals, %[ind]>=$1 && %[ind]<$1+2 )
+ "not $1(bp)"
+ samecc | | |
+lil adi sil $1==$3 && $2==2 | regorconst |
+ allocate(ADDREG={LOCAL2, $1, 2})
+ remove(referals)
+ "add (%[a]),%[1]"
+ setcc({ind_reg2, %[a]}) | | |
+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 | regorconst |
+ allocate(ADDREG={LOCAL2, $1, 2})
+ remove(referals)
+ "add (%[a]),%[1]"
+ setcc({ind_reg2, %[a]}) | | |
+lil adp sil $1==$3 | |
+ allocate(ADDREG={LOCAL2, $1, 2})
+ remove(referals)
+ "add (%[a]),$2"
+ setcc({ind_reg2, %[a]}) | | |
+lil adp sil $1==$3 && $2==1 | |
+ allocate(ADDREG={LOCAL2, $1, 2})
+ remove(referals)
+ "inc (%[a])"
+ setcc({ind_reg2, %[a]}) | | |
+lil adp sil $1==$3 && $2==0-1 | |
+ allocate(ADDREG={LOCAL2, $1, 2})
+ remove(referals)
+ "dec (%[a])"
+ setcc({ind_reg2, %[a]}) | | |
+lil and sil $1==$3 && $2==2 | regorconst |
+ allocate(ADDREG={LOCAL2, $1, 2})
+ remove(referals)
+ "and (%[a]),%[1]"
+ setcc({ind_reg2, %[a]}) | | |
+lil ior sil $1==$3 && $2==2 | regorconst |
+ allocate(ADDREG={LOCAL2, $1, 2})
+ remove(referals)
+ "or (%[a]),%[1]"
+ setcc({ind_reg2, %[a]}) | | |
+lil com sil $1==$3 && $2==2 | |
+ allocate(ADDREG={LOCAL2, $1, 2})
+ remove(referals)
+ "not (%[a])"
+ samecc | | |
+loe adi ste $1==$3 && $2==2 | regorconst |
+ remove(indirects)
+ "add ($1),%[1]"
+ setcc({EXTERN2, $1}) | | |
+loe ngi ste $1==$3 && $2==2 | |
+ remove(indirects)
+ "neg ($1)"
+ setcc({EXTERN2, $1}) | | |
+loe ads ste $1==$3 && $2==2 | regorconst |
+ remove(indirects)
+ "add ($1),%[1]"
+ setcc({EXTERN2, $1}) | | |
+loe adp ste $1==$3 | |
+ remove(indirects)
+ "add ($1),$2"
+ setcc({EXTERN2, $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 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 | | |
+
+/****************************************
+ * Group 8 : Convert instructions *
+ ****************************************/
+
+cii | CXREG DXREG X_ACC |
+ remove(ALL)
+ "call .cii"
+ erase(%[3]) | %[3] | |
+ciu | | | | cuu |
+cui | | | | cuu |
+cuu | CXREG BXREG X_ACC |
+ remove(ALL)
+ "call .cuu"
+ erase(%[3]) | %[3] | |
+cif | CXREG DXREG |
+ remove(ALL)
+ "call .cif" | | |
+cuf | CXREG DXREG |
+ remove(ALL)
+ "call .cuf" | | |
+cfi | CXREG DXREG |
+ remove(ALL)
+ "call .cfi" | | |
+cfu | CXREG DXREG |
+ remove(ALL)
+ "call .cfu" | | |
+cff | CXREG DXREG |
+ remove(ALL)
+ "call .cff" | | |
+loc loc cii $1==1 && $2==2 | ACC1 |
+ allocate(%[1],ACC)
+ "cbw"
+ samecc | %[a] | |(1,2)
+loc loc cii $1==1 && $2==4 | ACC1 |
+ allocate(%[1],ACC,DXREG)
+ "cbw"
+ "cwd"
+ samecc | dx ax | |(2,7)
+loc loc cii $1==2 && $2==4 | ACC |
+ allocate(DXREG)
+ "cwd"
+ samecc | dx ax | |(1,5)
+loc loc cii $1==4 && $2==2 | a_word a_word | | %[1] | |
+loc loc cuu $1==2 && $2==4 | a_word |
+ allocate(REG={ANYCON,0})| %[a] %[1] | |
+loc loc cuu $1==4 && $2==2 | a_word a_word | | %[1] | |
+loc loc ciu $1==2 && $2==4 | a_word |
+ allocate(REG={ANYCON,0})| %[a] %[1] | |
+loc loc ciu $1==4 && $2==2 | a_word a_word | | %[1] | |
+loc loc cui $1==2 && $2==4 | a_word |
+ allocate(REG={ANYCON,0})| %[a] %[1] | |
+loc loc cui $1==4 && $2==2 | a_word a_word | | %[1] | |
+
+/****************************************
+ * 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]
+... | 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]
+... | 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]
+... | 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]
+... | 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]
+... | 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]
+... | 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 |
+ remove(ALL)
+ "test %[1],%(1<<$1%)"
+ "je $3" | | |
+loc inn zne $2==2 | rm |
+ remove(ALL)
+ "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 |
+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" | di | |
+sar $1==2 | X_SIREG X_ACC X_DIREG |
+ remove(ALL)
+ "call .sar2"
+ erase(%[1]) erase(%[2]) erase(%[3])
+ | | |
+sar !defined($1) | | remove(ALL)
+ "call .isar" | | |
+lar $1==2 | X_DIREG X_ACC X_SIREG |
+ remove(ALL)
+ "call .lar2"
+ erase(%[1]) erase(%[2]) erase(%[3])
+ | | |
+lar !defined($1) | | remove(ALL)
+ "call .ilar" | | |
+
+/****************************************
+ * group 12 : Compare instructions *
+ ****************************************/
+
+cmi $1==2 | | | | sbi 2 |
+cmi $1==4 | rmorconst rmorconst X_REG X_REG |
+ "sub %[3],%[1]"
+ "sbb %[4],%[2]"
+ "jne 1f"
+ "and %[3],%[3]"
+ "je 1f"
+ "inc %[4]\n1: "
+ setcc(%[4]) erase(%[3]) erase(%[4])
+ | %[4] | |
+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]"
+ "jne 1f"
+ "or %[4],%[3]\n1: "
+ setcc(%[4]) erase(%[3]) erase(%[4])
+ | %[4] | |
+... | NO X_REG X_REG rmorconst rmorconst |
+ "sub %[1],%[3]"
+ "sbb %[2],%[4]"
+ "jne 1f"
+ "or %[2],%[1]\n1: "
+ 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 | |
+cmf $1==4 | |
+ remove(ALL)
+ "call .cmf4" | | |
+cmf $1==8 | |
+ remove(ALL)
+ "call .cmf8" | | |
+cmf !defined($1) | X_CXREG |
+ remove(ALL)
+ "call .cmf" erase(%[1]) | | |
+
+/* The costs with cmp are the cost of the 8086 cmp instruction */
+cmp | NO REG 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 REG |
+ 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 |
+ remove(ALL)
+ "cmp %[2],%[1]"
+ "jb $2" | | |
+... | NO rm regorconst |
+ remove(ALL)
+ "cmp %[1],%[2]"
+ "ja $2" | | |
+cmp zle | regorconst rm |
+ remove(ALL)
+ "cmp %[2],%[1]"
+ "jbe $2" | | |
+... | NO rm regorconst |
+ remove(ALL)
+ "cmp %[1],%[2]"
+ "jae $2" | | |
+cmp zeq | regorconst rm |
+ remove(ALL)
+ "cmp %[2],%[1]"
+ "je $2" | | |
+... | NO rm regorconst |
+ remove(ALL)
+ "cmp %[1],%[2]"
+ "je $2" | | |
+cmp zne | regorconst rm |
+ remove(ALL)
+ "cmp %[2],%[1]"
+ "jne $2" | | |
+... | NO rm regorconst |
+ remove(ALL)
+ "cmp %[1],%[2]"
+ "jne $2" | | |
+cmp zge | regorconst rm |
+ remove(ALL)
+ "cmp %[2],%[1]"
+ "jae $2" | | |
+... | NO rm regorconst |
+ remove(ALL)
+ "cmp %[1],%[2]"
+ "jbe $2" | | |
+cmp zgt | regorconst rm |
+ remove(ALL)
+ "cmp %[2],%[1]"
+ "ja $2" | | |
+... | NO rm regorconst |
+ remove(ALL)
+ "cmp %[1],%[2]"
+ "jb $2" | | |
+cms zeq $1==2 | regorconst rm |
+ remove(ALL)
+ "cmp %[2],%[1]"
+ "je $2" | | |
+... | NO rm regorconst |
+ remove(ALL)
+ "cmp %[1],%[2]"
+ "je $2" | | |
+cms zne $1==2 | regorconst rm |
+ remove(ALL)
+ "cmp %[2],%[1]"
+ "jne $2" | | |
+... | NO rm regorconst |
+ remove(ALL)
+ "cmp %[1],%[2]"
+ "jne $2" | | |
+and zeq $1==2 | regorconst rm |
+ remove(ALL)
+ "test %[2],%[1]"
+ "je $2" | | |
+... | NO rm regorconst |
+ remove(ALL)
+ "test %[1],%[2]"
+ "je $2" | | |
+and zne $1==2 | regorconst rm |
+ remove(ALL)
+ "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 |
+ remove(ALL)
+ "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 |
+ remove(ALL)
+ "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 |
+ remove(ALL)
+ "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 |
+ remove(ALL)
+ "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 |
+ remove(ALL)
+ "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 |
+ remove(ALL)
+ "cmp %[1],$1"
+ "jne $3" | | | (2,3) + %[1]
+
+/****************************************
+ * Group 13 : Branch instructions *
+ ****************************************/
+
+bra | | remove(ALL)
+ "jmp $1"
+ samecc | | |
+blt | regorconst rm |
+ remove(ALL)
+ "cmp %[2],%[1]"
+ "jl $1" | | |
+... | NO rm regorconst |
+ remove(ALL)
+ "cmp %[1],%[2]"
+ "jg $1" | | |
+ble | regorconst rm |
+ remove(ALL)
+ "cmp %[2],%[1]"
+ "jle $1" | | |
+... | NO rm regorconst |
+ remove(ALL)
+ "cmp %[1],%[2]"
+ "jge $1" | | |
+beq | regorconst rm |
+ remove(ALL)
+ "cmp %[2],%[1]"
+ "je $1" | | |
+... | NO rm regorconst |
+ remove(ALL)
+ "cmp %[1],%[2]"
+ "je $1" | | |
+bne | regorconst rm |
+ remove(ALL)
+ "cmp %[2],%[1]"
+ "jne $1" | | |
+... | NO rm regorconst |
+ remove(ALL)
+ "cmp %[1],%[2]"
+ "jne $1" | | |
+bge | regorconst rm |
+ remove(ALL)
+ "cmp %[2],%[1]"
+ "jge $1" | | |
+... | NO rm regorconst |
+ remove(ALL)
+ "cmp %[1],%[2]"
+ "jle $1" | | |
+bgt | regorconst rm |
+ remove(ALL)
+ "cmp %[2],%[1]"
+ "jg $1" | | |
+... | NO rm regorconst |
+ remove(ALL)
+ "cmp %[1],%[2]"
+ "jl $1" | | |
+zlt | rm |
+ remove(ALL)
+ test(%[1])
+ "jl $1" | | |
+zle | rm |
+ remove(ALL)
+ test(%[1])
+ "jle $1" | | |
+zeq | rm+rm1 |
+ remove(ALL)
+ test(%[1])
+ "je $1" | | |
+zne | rm+rm1 |
+ remove(ALL)
+ test(%[1])
+ "jne $1" | | |
+zge | rm |
+ remove(ALL)
+ test(%[1])
+ "jge $1" | | |
+zgt | rm |
+ remove(ALL)
+ 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 | | | bx dx ax | |
+lfr $1==8 | | | cx bx dx ax | |
+ret $1==0 | | remove(ALL)
+ "mov sp,bp"
+ "pop bp"
+ "ret" | | |
+ret $1==2 | ACC |
+ "mov sp,bp"
+ "pop bp"
+ "ret" | | |
+ret $1==4 | ACC DXREG |
+ "mov sp,bp"
+ "pop bp"
+ "ret" | | |
+ret $1==6 | ACC DXREG BXREG |
+ "mov sp,bp"
+ "pop bp"
+ "ret" | | |
+ret $1==8 | ACC DXREG BXREG CXREG |
+ "mov sp,bp"
+ "pop bp"
+ "ret" | | |
+
+/************************************************
+ * Group 15 : Miscellaneous instructions *
+ ************************************************/
+
+asp $1==2 | nocoercions : a_word | | | |
+... | STACK |
+ allocate(IREG) /* GENREG may contain lfr area */
+ "pop %[a]" erase(%[a]) samecc | | | (1,8)
+asp $1==4 | nocoercions : a_word a_word | | | |
+... | STACK |
+ allocate(IREG) /* GENREG may contain lfr area */
+ "pop %[a]" "pop %[a]"
+ erase(%[a]) samecc | | | (2,16)
+asp $1==0-2 | | /* Anything will do */ | bp | |
+... | | remove(ALL)
+ "push lb" | | | (1,10)
+asp | | remove(ALL)
+ "add sp,$1" | | | (4,4)
+ass $1==2 | rmorconst |
+ remove(ALL)
+ "add sp,%[1]" | | |
+ass !defined($1)| rm rmorconst |
+ remove(ALL)
+ "cmp %[1],2"
+ "jne .unknown"
+ "add sp,%[2]" | | |
+blm $1==0 | | | | asp 4 |
+blm $1>0 | X_DIREG X_SIREG |
+ remove(ALL)
+ allocate(CXREG={ANYCON,$1/2})
+ "rep movs"
+ erase(%[1]) erase(%[2]) erase(%[a])
+ | | |
+bls $1==2 | X_CXREG X_DIREG X_SIREG |
+ remove(ALL)
+ "sar cx,1"
+ "rep movs"
+ erase(%[1]) erase(%[2]) erase(%[3])
+ | | |
+bls !defined($1)| rm-CXREG-DIREG-SIREG X_CXREG X_DIREG X_SIREG |
+ remove(ALL)
+ "cmp %[1],2"
+ "jne .unknown"
+ "sar cx,1"
+ "rep movs"
+ erase(%[2]) erase(%[3]) erase(%[4])
+ | | |
+csa $1==2 | X_SIREG X_BXREG |
+ remove(ALL)
+ "jmp .csa2"
+ erase(%[1]) erase(%[2]) | | |
+csa !defined($1)| rm-SIREG-BXREG X_SIREG X_BXREG |
+ remove(ALL)
+ "cmp %[1],2"
+ "jne .unknown"
+ "jmp .csa2"
+ erase(%[2]) erase(%[3]) | | |
+csb $1==2 | X_SIREG X_DXREG |
+ remove(ALL)
+ "jmp .csb2"
+ erase(%[1]) erase(%[2]) | | |
+csb !defined($1)| rm-SIREG-DIREG X_SIREG X_DXREG |
+ remove(ALL)
+ "cmp %[1],2"
+ "jne .unknown"
+ "jmp .csb2"
+ erase(%[2]) erase(%[3]) | | |
+dup $1==2 | REG | | %[1] %[1] | |
+dup $1==4 | REG REG | | %[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 | | remove(ALL)
+ 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 | SIREG ACC |
+ "call .rck" | ax | |
+rck !defined($1)| rm-SIREG-ACC SIREG 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 |
+ remove(ALL)
+ "mov sp,%[1]" | | |
+str $1==2 | |
+ remove(ALL)
+ "call .strhp" | | |
+trp | X_ACC |
+ remove(ALL)
+ "call .trp" | | |
+
+/********************************
+ * From source to register *
+ ********************************/
+
+| rmorconst | allocate(%[1],REG=%[1]) | %[a] | |
+| reg_off | "add %[1.reg],%[1.off]"
+ erase(%[1.reg]) setcc(%[1.reg])
+ | %[1.reg] | |(2,3) + %[1]
+#ifdef DEEPER
+| halfindir |
+ allocate(%[1],REG)
+ move(%[1],%[a])
+ samecc | %[a] | |(0,0)
+#else
+| halfindir |
+ allocate(%[1],ADDREG)
+ move(%[1],%[a])
+ samecc | %[a] | |(0,0)
+#endif
+
+/********************************
+ * 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, REG, "mov %[2],%[1]" samecc, (2,2) + %[1] )
+(anyreg, dest, "mov %[2],%[1]" samecc, (2,3) + %[2] )
+(halfindir, REG, "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, REG, "xor %[2],%[2]" setcc(%[2]), (2,3))
+(ANYCON %[val]==0, REG1, "xorb %[2],%[2]" setcc(%[2]),(2,3))
+(const, REG, "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, , ".data\n1: .word %[1]\n.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] )
+(reg_off, , "add %[1.reg],%[1.off]"
+ "push %[1.reg]"
+ erase(%[1.reg])
+ setcc(%[1.reg]) , ( 4,14) )
+(bpreg_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] )