"$Header$" /* * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands. * * This product is part of the Amsterdam Compiler Kit. * * Permission to use, sell, duplicate or disclose this software must be * obtained in writing. Requests for such permissions may be sent to * * Dr. Andrew S. Tanenbaum * Wiskundig Seminarium * Vrije Universiteit * Postbox 7161 * 1007 MC Amsterdam * The Netherlands * */ #define SL 4 #define SSL "4" /******************************************************** * 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} | | loe loe $1==$2 | | allocate(ADDREG={EXTERN2, $1}) | %[a] %[a] | | lol lol $1==$2 | | allocate(ADDREG={LOCAL2, $1, 2})| %[a] %[a] | | 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 | | | ... | nocoercions : ADDR_LOCAL | | | stl %[1.ind] | ... | bpreg_off regorconst | remove(all_locals) remove(indexed) move(%[2],{ind_bpregoff2,%[1.reg], %[1.ind]}) | | | ... | nocoercions : bpreg_off STACK | remove(all_locals) remove(indexed) "pop %[1]" samecc | | | ... | ADDR_EXTERN regorconst | remove(indirects) move(%[2],{EXTERN2,%[1.off]}) | | | ... | nocoercions : ADDR_EXTERN STACK | remove(indirects) "pop (%[1])" samecc | | | sti $1==1 | ADDREG regorconst12 | remove(referals) move(%[2],{ind_reg1,%[1]}) | | | ... | reg_off regorconst12 | remove(referals) move(%[2],{ind_regoff1,%[1.reg],%[1.off]}) | | | ... | bpreg_off regorconst12 | remove(all_locals) remove(indexed) move(%[2],{ind_bpregoff1,%[1.reg], %[1.ind]}) | | | ... | ADDR_EXTERN regorconst12 | remove(indirects) move(%[2],{EXTERN1,%[1.off]}) | | | ... | ADDR_LOCAL regorconst12 | remove(indexed) remove(locals, %[ind]<=%[1.ind] && %[ind]+%[size]>%[1.ind] ) move(%[2],{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 */ ... | nocoercions: ADDR_LOCAL | | | stl %[1.ind]+$1 stl %[1.ind]+$1+2 | ... | bpreg_off regorconst regorconst | remove(all_locals) remove(indexed) move(%[2],{ind_bpregoff2,%[1.reg], %[1.ind]+$1}) move(%[3],{ind_bpregoff2,%[1.reg], %[1.ind]+$1+2}) | | | ... | halfindir regorconst | remove(referals) "mov %[1],%[2]" samecc | %[1] | stf $1+2 | (0,12)+%[1]+%[2]+%[1] /**************************************************************** * Group 3 : Integer arithmetic. * * * * Implemented (sometimes with the use of subroutines) : * * all 2 and 4 byte arithmetic. * ****************************************************************/ adi $1==2 | NO X_REG rmorconst | "add %[1],%[2]" erase(%[1]) setcc(%[1]) | %[1] | | (2,3) + %[2] ... | rmorconst X_REG | "add %[2],%[1]" erase(%[2]) setcc(%[2]) | %[2] | | (2,3) + %[1] ... | X_ACC const | "add %[1],%[2]" erase(%[1]) setcc(%[1]) | %[1] | | (3,4) ... | const X_ACC | "add %[2],%[1]" erase(%[2]) setcc(%[2]) | %[2] | | (3,4) adi $1==4 | NO X_REG X_REG rmorconst rmorconst | "add %[1],%[3]" "adc %[2],%[4]" setcc(%[2]) erase(%[1]) erase(%[2]) | %[2] %[1] | |(4,6)+%[4]+%[3] ... | 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) ... | X_ADDREG | | {reg_off, %[1], tostring($1)} | | 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) ... | X_ADDREG | | {reg_off, %[1], tostring($1)} | | 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}) | | | ldl adi sdl $1==$3 && $2==4 | regorconst regorconst | remove(indexed) remove(locals, %[ind]>=$1 && %[ind]<$1+4 ) "add $1(bp),%[1]" "adc %($1+2%)(bp),%[2]" | | | lol ngi stl $1==$3 && $2==2 | | remove(indexed) remove(locals, %[ind]>=$1 && %[ind]<$1+2 ) "neg $1(bp)" setcc({LOCAL2, $1, 2}) | | | ldl ngi sdl $1==$3 && $2==4 | | remove(indexed) remove(locals, %[ind]>=$1 && %[ind]<$1+4 ) "neg $1(bp)" "neg %($1+2%)(bp)" "sbb %($1+2%)(bp),0" | | | lol ads stl $1==$3 && $2==2 | regorconst | remove(indexed) remove(locals, %[ind]>=$1 && %[ind]<$1+2 ) "add $1(bp),%[1]" setcc({LOCAL2, $1, 2}) | | | lol lol adp stl $1==$2 && $1==$4 | | allocate(ADDREG={LOCAL2,$1,2}) | %[a] | lol $2 adp $3 stl $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 adp stl $1==$3 | | remove(indexed) remove(locals, %[ind]>=$1 && %[ind]<$1+2 ) "add $1(bp),$2" 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 && $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 adp sil $1==$3 | | allocate(ADDREG={LOCAL2, $1, 2}) remove(referals) "add (%[a]),$2" 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}) | | | lde adi sde $1==$3 && $2==4 | regorconst regorconst | remove(indirects) "add ($1),%[1]" "adc ($1+2),%[2]" | | | loe ngi ste $1==$3 && $2==2 | | remove(indirects) "neg ($1)" setcc({EXTERN2, $1}) | | | lde ngi sde $1==$3 && $2==4 | | remove(indirects) "neg ($1)" "neg ($1+2)" "sbb ($1+2),0" | | | loe ads ste $1==$3 && $2==2 | regorconst | remove(indirects) "add ($1),%[1]" setcc({EXTERN2, $1}) | | | loe loe adp ste $1==$4 && $1==$4 | | allocate(ADDREG={EXTERN2,$1}) | %[a] | loe $1 adp $3 ste $1 | loe adp ste $1==$3 && $2==1 | | remove(indirects) "inc ($1)" setcc({EXTERN2, $1}) | | | loe adp ste $1==$3 && $2==0-1 | | remove(indirects) "dec ($1)" setcc({EXTERN2, $1}) | | | loe adp ste $1==$3 | | remove(indirects) "add ($1),$2" setcc({EXTERN2, $1}) | | | loe and ste $1==$3 && $2==2 | regorconst | remove(indirects) "and ($1),%[1]" setcc({EXTERN2, $1}) | | | loe ior ste $1==$3 && $2==2 | regorconst | remove(indirects) "or ($1),%[1]" setcc({EXTERN2, $1}) | | | loe com ste $1==$3 && $2==2 | | remove(indirects) "not ($1)" samecc | | | /**************************************** * 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 | ACC | "cbw" samecc | ax | |(1,2) ... | ACC1 | "cbw" samecc | ax | |(1,2) loc loc cii $1==1 && $2==4 | ACC | allocate(DXREG) "cbw" "cwd" samecc | dx ax | |(2,7) ... | ACC1 | allocate(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 ciu | | | | loc $1 loc $2 cuu | loc loc cui | | | | loc $1 loc $2 cuu | loc loc cuu $1==$2 | | | | | loc loc cuu $1==2 && $2==4 | a_word | allocate(REG={ANYCON,0})| %[a] %[1] | | loc loc cuu $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] | | ... | ACC1 | | %[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] )