diff --git a/mach/i86/cg/table b/mach/i86/cg/table new file mode 100644 index 000000000..482fd6085 --- /dev/null +++ b/mach/i86/cg/table @@ -0,0 +1,2327 @@ +/* + * (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] )