"$Header$" /* * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands. * * This product is part of the Amsterdam Compiler Kit. * * Permission to use, sell, duplicate or disclose this software must be * obtained in writing. Requests for such permissions may be sent to * * Dr. Andrew S. Tanenbaum * Wiskundig Seminarium * Vrije Universiteit * Postbox 7161 * 1007 MC Amsterdam * The Netherlands * */ #define SL 4 #define SSL "4" #define REGVARS /******************************************************** * Back end tables for Intel 8086 * * Author : Ed Keizer * * * * 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. #ifdef REGVARS si = ("si", 2) regvar, RREG, RADDREG. di = ("di", 2) regvar, RREG, RADDREG. #else si = ("si", 2), REG, IREG, SIREG, ADDREG. di = ("di", 2), REG, IREG, DIREG, ADDREG. #endif bp = ("bp", 2), BREG. TOKENS: /******************************** * Types on the EM-machine * ********************************/ ANYCON = { INT val ; } 2 cost=(2, 1) "%[val]" ADDR_EXTERN = { STRING off ; } 2 cost=(2, 1) "%[off]" EXTERN1 = { STRING off ; } 2 cost=(2,12) "(%[off])" EXTERN2 = { STRING off ; } 2 cost=(2,12) "(%[off])" ADDR_LOCAL = { INT ind ; } 2 cost=(1, 9) "%[ind](bp)" LOCAL2 = { INT ind, size ; } 2 cost=(1,15) "%[ind](bp)" LOCAL1 = { INT ind, size ; } 2 cost=(1,15) "%[ind](bp)" /******************************************************** * Now mostly addressing modes of target machine * ********************************************************/ /***************************************** * 'Half modes' consisting of summations * * of constant and or register(s) * *****************************************/ 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 #ifndef REGVARS X_SIREG = SIREG*SCRATCH X_DIREG = DIREG*SCRATCH #endif X_ADDREG = ADDREG*SCRATCH #ifdef REGVARS IREG = RREG #endif /* Mode refering to a word in memory */ memory2 = EXTERN2 + ind_reg2 + ind_regoff2 + ind_bpregoff2 + LOCAL2 /* Mode refering to a byte in memory */ memory1 = EXTERN1 + ind_reg1 + ind_regoff1 + ind_bpregoff1 + LOCAL1 /* Modes allowed in instructions */ const = ANYCON + ADDR_EXTERN register = REG #ifdef REGVARS + RREG #endif anyreg = register + BREG addreg = ADDREG #ifdef REGVARS + RADDREG #endif rm = anyreg + memory2 rmnoacc = RREG + BREG + CXREG + memory2 rmorconst = const + rm noregvar = const + REG + BREG + memory2 regorconst = const + anyreg #ifdef REGVARS /* Needed because there is a shortage of ADDREG-registers. This is the main penalty for having register variables. */ regorconstnoaddr = const + RREG + ACC + CXREG + DXREG #else regorconstnoaddr = regorconst #endif dest = register + memory2 rm1 = REG1 + memory1 rmorconst1 = const + rm1 regorconst12 = REG1 + GENREG + const dest1 = REG1 + memory1 /* Modes used to indicate tokens to be removed from the fakestack */ reg_indexed = ind_reg2 + ind_regoff2 + ind_reg1 + ind_regoff1 lb_indexed = ind_bpregoff2 + ind_bpregoff1 indexed = reg_indexed + lb_indexed externals = EXTERN2 + EXTERN1 locals = LOCAL2 + LOCAL1 all_locals = locals + lb_indexed indirects = externals + reg_indexed referals = indirects + locals /* Miscellaneous */ halfindir = reg_off + bpreg_off + ADDR_LOCAL some_off = halfindir + ADDR_EXTERN + addreg x_word = rmorconst + halfindir 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)} | | #ifdef REGVARS lol inreg($1)==2 | | | regvar($1) | | #endif lol | | | {LOCAL2, $1, 2} | | loe | | | {EXTERN2, $1} | | loe loe $1==$2 | | allocate(REG={EXTERN2, $1}) | %[a] %[a] | | #ifdef REGVARS lol lol $1==$2 && inreg($1)!=2 | | allocate(REG={LOCAL2, $1, 2})| %[a] %[a] | | #else lol lol $1==$2 | | allocate(REG={LOCAL2, $1, 2})| %[a] %[a] | | #endif #ifdef REGVARS lil inreg($1)==2 | | | {ind_reg2, regvar($1)} | | #endif lil | | allocate(ADDREG={ind_regoff2, bp, tostring($1)}) | {ind_reg2, %[a]} | | lof | nocoercions : reg_off | | {ind_regoff2, %[1.reg], %[1.off]+"+"+tostring($1)} | | ... | addreg | | {ind_regoff2,%[1],tostring($1)} | | ... | nocoercions : bpreg_off | | {ind_bpregoff2,%[1.reg], %[1.ind]+$1} | | ... | nocoercions : ADDR_EXTERN| | {EXTERN2,%[1.off]+"+"+tostring($1)} | | ... | nocoercions : ADDR_LOCAL | | {LOCAL2, %[1.ind] + $1,2} | | lal | | | {ADDR_LOCAL, $1} | | lae | | | {ADDR_EXTERN, $1} | | lpb | | | | adp SL | lxl $1==0 | | | {ADDR_LOCAL, 0} | | lxl $1==1 | | | {LOCAL2 ,SL, 2} | | lxl $1==2 | | allocate(ADDREG={ind_regoff2, bp, SSL}) | {ind_regoff2,%[a], SSL} | | lxl $1>2 | | allocate(ADDREG={ind_regoff2, bp, SSL}, CXREG={ANYCON,$1-1}) "1:\tmov %[a],4(%[a])" "loop 1b" samecc erase(%[a]) erase(%[b]) | %[a] | | lxa $1==0 | | | {ADDR_LOCAL, SL} | | lxa $1==1 | | allocate(ADDREG={ind_regoff2, bp, SSL }) | {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 | noregvar | remove(ALL) allocate(CXREG={ANYCON,$1/2}) "mov ax,si" "mov bx,di" "mov si,%[1]" "sub sp,%($1%)" "mov di,sp" "rep movs" "mov si,ax" "mov di,bx" erase(%[a]) | | | (16,16+$1*9) ... | X_BXREG | remove(ALL) allocate(CXREG={ANYCON,$1}) "call .loi" erase(%[a]) erase(%[1]) | | | (3,40+$1*9) los $1==2 | X_CXREG X_BXREG | remove(ALL) "call .loi" erase(%[1]) erase(%[2]) | | | los !defined($1)| rm X_CXREG X_BXREG | 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. * ****************************************************************/ #ifdef REGVARS stl inreg($1)==2 | rmorconst | move(%[1], regvar($1)) | | | ... | nocoercions : STACK | "pop %(regvar($1)%)" samecc | | |(1,8) #endif stl | regorconst | remove(indexed) remove(locals, %[ind]>=$1 && %[ind]<$1+2 ) move(%[1],{ind_regoff2,bp,tostring($1)})| | | ... | nocoercions : STACK | "pop $1(bp)" samecc | | |(2,26) ste | regorconst | remove(indirects) move(%[1], {EXTERN2, $1 }) | | | ... | nocoercions : STACK | "pop ($1)" samecc | | | #ifdef REGVARS sil inreg($1)==2| regorconst | remove(referals) move(%[1],{ind_reg2, regvar($1)}) | | | ... | nocoercions : STACK | "pop (%(regvar($1)%)" samecc | | |(2,26) #endif sil | regorconstnoaddr | allocate(ADDREG={ind_regoff2, bp, tostring($1)}) remove(referals) move(%[1], {ind_reg2, %[a]}) | | | ... | STACK | allocate(ADDREG={ind_regoff2, bp, tostring($1)}) remove(referals) "pop (%[a])" samecc | | | (2,26) stf | addreg regorconst | remove(referals) move(%[2],{ind_regoff2,%[1],tostring($1)})| | | ... | nocoercions : addreg STACK | remove(referals) "pop $1(%[1])" samecc | | | ... | reg_off regorconst | remove(referals) move(%[2],{ind_regoff2,%[1.reg], %[1.off]+"+"+tostring($1)}) | | | ... | nocoercions : halfindir STACK | remove(referals) "pop $1+%[1]" samecc | | | ... | nocoercions : ADDR_LOCAL | | | stl %[1.ind]+$1 | ... | bpreg_off regorconst | remove(all_locals) remove(indexed) move(%[2],{ind_bpregoff2,%[1.reg], %[1.ind]+$1}) | | | /* ... | ADDR_EXTERN regorconst | remove(indirects) move(%[2],{EXTERN2,%[1.off]+"+"+tostring($1)})| | | */ sti $1==2 | addreg regorconst | remove(referals) move(%[2],{ind_reg2,%[1]}) | | | ... | nocoercions : addreg STACK | remove(referals) "pop (%[1])" samecc | | | ... | reg_off regorconst | remove(referals) move(%[2],{ind_regoff2,%[1.reg],%[1.off]}) | | | ... | nocoercions : reg_off STACK | remove(referals) "pop %[1]" samecc | | | ... | nocoercions : ADDR_LOCAL | | | stl %[1.ind] | ... | bpreg_off regorconst | remove(all_locals) remove(indexed) move(%[2],{ind_bpregoff2,%[1.reg], %[1.ind]}) | | | ... | nocoercions : bpreg_off STACK | remove(all_locals) remove(indexed) "pop %[1]" samecc | | | ... | ADDR_EXTERN regorconst | remove(indirects) move(%[2],{EXTERN2,%[1.off]}) | | | ... | nocoercions : ADDR_EXTERN STACK | remove(indirects) "pop (%[1])" samecc | | | sti $1==1 | addreg regorconst12 | remove(referals) move(%[2],{ind_reg1,%[1]}) | | | ... | reg_off regorconst12 | remove(referals) move(%[2],{ind_regoff1,%[1.reg],%[1.off]}) | | | ... | bpreg_off regorconst12 | remove(all_locals) remove(indexed) move(%[2],{ind_bpregoff1,%[1.reg], %[1.ind]}) | | | ... | ADDR_EXTERN regorconst12 | remove(indirects) move(%[2],{EXTERN1,%[1.off]}) | | | ... | ADDR_LOCAL regorconst12 | remove(indexed) remove(locals, %[ind]<=%[1.ind] && %[ind]+%[size]>%[1.ind] ) move(%[2],{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 | noregvar | remove(ALL) allocate(CXREG={ANYCON,$1/2}) "mov ax,si" "mov bx,di" "mov si,sp" "mov di,%[1]" "rep movs" "mov sp,si" "mov si,ax" "mov di,bx" erase(%[a]) | | | (14,12+$1*8) ... | X_BXREG | remove(ALL) allocate(CXREG={ANYCON,$1}) "call .sti" erase(%[a]) erase(%[1]) | | | (3,40+$1*9) /* This sort of construction gives problems in the codegenerator because of the potential verly large lookahead ... | X_ADDREG | remove(ALL) "pop (%[1])" "add %[1],2" erase(%[1]) | %[1] | sti $1-2 | (5,30) */ sts $1==2 | X_CXREG X_BXREG | remove(ALL) "call .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] ... | rmnoacc rmorconst | allocate(%[2],ACC=%[2],DXREG) "mul %[1]" nocc erase(%[a]) | ax | |(2,118)+%[1] mli $1==4 | X_ACC X_DXREG | remove(ALL) "call .mli4" erase(ax) erase(dx) setcc(dx) | dx ax | | /* Not now, mli !defined($1)| X_ACC | remove(ALL) "call .mli" | | | */ dvi $1==2 | rmnoacc rmorconst | allocate(%[2], ACC=%[2], DXREG) "cwd" "idiv %[1]" erase(%[a]) | ax | |(3,176)+%[1] dvi $1==4 | | remove(ALL) "call .dvi4" | dx ax | | /* dvi !defined($1)| X_ACC | remove(ALL) "call .dvi" erase(%[1]) | | | */ #ifdef LONGEMPAT loc loc cii dvi loc loc cii $1==2 && $2==4 && $4==4 && $5==4 && $6==2 | rmnoacc X_ACC X_DXREG | "idiv %[1]" erase(%[2]) erase(%[3]) | ax | |(2,171)+%[1] #endif rmi $1==2 | rmnoacc rmorconst | allocate(%[2], ACC=%[2], DXREG) "cwd" "idiv %[1]" erase(%[a]) | dx | |(3,176)+%[1] rmi $1==4 | | remove(ALL) "call .rmi4" | dx ax | | /* rmi !defined($1)| X_ACC | remove(ALL) "call .rmi" erase(%[1]) | | | */ #ifdef LONGEMPAT loc loc cii rmi loc loc cii $1==2 && $2==4 && $4==4 && $5==4 && $6==2 | rmnoacc 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) /* 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 | rmnoacc rmorconst | allocate(%[2],ACC=%[2],DXREG={ANYCON,0}) "div %[1]" erase(%[b]) erase(%[a]) | ax | |(2,149)+%[1] dvu $1==4 | | remove(ALL) "call .dvu4" | dx ax | | /* dvu !defined($1)| X_ACC | remove(ALL) "call .dvu" erase(%[1]) | | | */ rmu $1==2 | rmnoacc rmorconst | allocate(%[2],ACC=%[2],DXREG={ANYCON,0}) "div %[1]" erase(%[b]) erase(%[a]) | dx | |(3,149)+%[1] rmu $1==4 | | remove(ALL) "call .rmu4" | dx ax | | /* rmu !defined($1)| X_ACC | remove(ALL) "call .rmu" erase(%[1]) | | | */ slu | | | | sli $1 | loc 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) #ifndef REGVARS ... | IREG ADDR_LOCAL | | {bpreg_off,%[1],%[2.ind]} | | /* ... | (REG-IREG) ADDR_LOCAL | allocate(%[1],ADDREG=%[1]) "add %[a],bp" | {reg_off, %[a], tostring(%[2.ind])} | | (2,3) */ #else ... | nocoercions: RREG ADDR_LOCAL | | {bpreg_off,%[1],%[2.ind]} | | #endif #ifdef DEEPER ... | X_REG rmorconst | "add %[1],%[2]" erase(%[1]) setcc(%[1]) | %[1] | | (2,3) + %[2] ... | rmorconst X_REG | "add %[2],%[1]" erase(%[2]) setcc(%[2]) | %[2] | | (2,3) + %[1] ... | X_ACC const | "add %[1],%[2]" erase(%[1]) setcc(%[1]) | %[1] | | (3,4) ... | const X_ACC | "add %[2],%[1]" erase(%[2]) setcc(%[2]) | %[2] | | (3,4) #else ... | X_ADDREG ADDR_EXTERN | | {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) #ifdef REGVARS inl inreg($1)==2| | "inc %(regvar($1)%)" setcc(regvar($1)) | | |(1,2) #endif inl | | remove(indexed) remove(locals, %[ind]>=$1 && %[ind]<$1+2 ) "inc $1(bp)" setcc({LOCAL2,$1,2}) | | |(3,24) ine | | remove(indirects) "inc ($1)" setcc({EXTERN2,$1}) | | |(4,21) dec | X_REG | "dec %[1]" setcc(%[1]) erase(%[1]) | %[1] | |(1,2) #ifdef REGVARS del inreg($1)==2| | "dec %(regvar($1)%)" setcc(regvar($1)) | | |(1,2) #endif del | | remove(indexed) remove(locals, %[ind]>=$1 && %[ind]<$1+2 ) "dec $1(bp)" setcc({LOCAL2,$1,2}) | | |(3,24) dee | | remove(indirects) "dec ($1)" setcc({EXTERN2,$1}) | | |(4,21) #ifdef REGVARS zrl inreg($1)==2| | move({ANYCON,0},regvar($1)) | | | #endif zrl | | remove(indexed) remove(locals, %[ind]>=$1 && %[ind]<$1+2 ) move({ANYCON,0},{LOCAL2,$1,2}) | | | zre | | remove(indirects) move({ANYCON,0},{EXTERN2,$1})| | | 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]) | | | #ifdef REGVARS lol adi stl $1==$3 && $2==2 && inreg($1)==2 | rmorconst | "add %(regvar($1)%),%[1]" setcc(regvar($1)) | | | #endif lol adi stl $1==$3 && $2==2 | regorconst | remove(indexed) remove(locals, %[ind]>=$1 && %[ind]<$1+2 ) "add $1(bp),%[1]" setcc({LOCAL2, $1, 2}) | | | ldl adi sdl $1==$3 && $2==4 | regorconst regorconst | remove(indexed) remove(locals, %[ind]>=$1 && %[ind]<$1+4 ) "add $1(bp),%[1]" "adc %($1+2%)(bp),%[2]" | | | #ifdef REGVARS lol ngi stl $1==$3 && $2==2 && inreg($1)==2 | | "neg %(regvar($1)%)" setcc(regvar($1)) | | | #endif lol ngi stl $1==$3 && $2==2 | | remove(indexed) remove(locals, %[ind]>=$1 && %[ind]<$1+2 ) "neg $1(bp)" setcc({LOCAL2, $1, 2}) | | | ldl ngi sdl $1==$3 && $2==4 | | remove(indexed) remove(locals, %[ind]>=$1 && %[ind]<$1+4 ) "neg $1(bp)" "neg %($1+2%)(bp)" "sbb %($1+2%)(bp),0" | | | lol ads stl $1==$3 && $2==2 | | | | lol $1 adi 2 stl $1 | #ifdef REGVARS lol lol adp stl $1==$2 && $1==$4 && inreg($1)==2 | | allocate(ADDREG=regvar($1)) | %[a] | lol $2 adp $3 stl $2 | lol inl $1==$2 && inreg($1)==2 | | allocate(REG=regvar($1)) | %[a] | inl $1 | lol del $1==$2 && inreg($1)==2 | | allocate(REG=regvar($1)) | %[a] | del $1 | #endif lol lol adp stl $1==$2 && $1==$4 | | allocate(ADDREG={LOCAL2,$1,2}) | %[a] | lol $2 adp $3 stl $2 | lol inl $1==$2 | | allocate(REG={LOCAL2,$1,2}) | %[a] | inl $1 | lol del $1==$2 | | allocate(REG={LOCAL2,$1,2}) | %[a] | del $1 | lol adp stl $1==$3 && $2==1 | | | | inl $1 | lol adp stl $1==$3 && $2==0-1 | | | | del $1 | #ifdef REGVARS lol adp stl $1==$3 && inreg($1)==2 | | "add %(regvar($1)%),$2" setcc(regvar($1)) | | | #endif lol adp stl $1==$3 | | remove(indexed) remove(locals, %[ind]>=$1 && %[ind]<$1+2 ) "add $1(bp),$2" setcc({LOCAL2, $1, 2}) | | | #ifdef REGVARS lol and stl $1==$3 && $2==2 && inreg($1)==2 | rmorconst | "and %(regvar($1)%),%[1]" setcc(regvar($1)) | | | #endif lol and stl $1==$3 && $2==2 | regorconst | remove(indexed) remove(locals, %[ind]>=$1 && %[ind]<$1+2 ) "and $1(bp),%[1]" setcc({LOCAL2, $1, 2}) | | | #ifdef REGVARS lol ior stl $1==$3 && $2==2 && inreg($1)==2 | rmorconst | "or %(regvar($1)%),%[1]" setcc(regvar($1)) | | | #endif lol ior stl $1==$3 && $2==2 | regorconst | remove(indexed) remove(locals, %[ind]>=$1 && %[ind]<$1+2 ) "or $1(bp),%[1]" setcc({LOCAL2, $1, 2}) | | | #ifdef REGVARS lol com stl $1==$3 && $2==2 && inreg($1)==2 | | "not %(regvar($1)%)" samecc | | | #endif lol com stl $1==$3 && $2==2 | | remove(indexed) remove(locals, %[ind]>=$1 && %[ind]<$1+2 ) "not $1(bp)" samecc | | | #ifdef REGVARS lil adi sil $1==$3 && $2==2 && inreg($1)==2 | regorconst | remove(referals) "add (%(regvar($1)%)),%[1]" setcc({ind_reg2, regvar($1)}) | | | #endif lil adi sil $1==$3 && $2==2 | regorconstnoaddr | allocate(ADDREG={LOCAL2, $1, 2}) remove(referals) "add (%[a]),%[1]" setcc({ind_reg2, %[a]}) | | | #ifdef REGVARS lil ngi sil $1==$3 && $2==2 && inreg($1)==2 | | remove(referals) "neg (%(regvar($1)%))" setcc({ind_reg2, regvar($1)}) | | | #endif lil ngi sil $1==$3 && $2==2 | | allocate(ADDREG={LOCAL2, $1, 2}) remove(referals) "neg (%[a])" setcc({ind_reg2, %[a]}) | | | lil ads sil $1==$3 && $2==2 | | | | lil $1 adi 2 sil $1 | #ifdef REGVARS lil adp sil $1==$3 && $2==1 && inreg($1)==2 | | remove(referals) "inc (%(regvar($1)%))" setcc({ind_reg2, regvar($1)}) | | | #endif lil adp sil $1==$3 && $2==1 | | allocate(ADDREG={LOCAL2, $1, 2}) remove(referals) "inc (%[a])" setcc({ind_reg2, %[a]}) | | | #ifdef REGVARS lil adp sil $1==$3 && $2==0-1 && inreg($1)==2 | | remove(referals) "dec (%(regvar($1)%))" setcc({ind_reg2, regvar($1)}) | | | #endif lil adp sil $1==$3 && $2==0-1 | | allocate(ADDREG={LOCAL2, $1, 2}) remove(referals) "dec (%[a])" setcc({ind_reg2, %[a]}) | | | #ifdef REGVARS lil adp sil $1==$3 && inreg($1)==2 | | remove(referals) "add (%(regvar($1)%)),$2" setcc({ind_reg2, regvar($1)}) | | | #endif lil adp sil $1==$3 | | allocate(ADDREG={LOCAL2, $1, 2}) remove(referals) "add (%[a]),$2" setcc({ind_reg2, %[a]}) | | | #ifdef REGVARS lil and sil $1==$3 && $2==2 && inreg($1)==2 | regorconst | remove(referals) "and (%(regvar($1)%)),%[1]" setcc({ind_reg2, regvar($1)}) | | | #endif lil and sil $1==$3 && $2==2 | regorconstnoaddr | allocate(ADDREG={LOCAL2, $1, 2}) remove(referals) "and (%[a]),%[1]" setcc({ind_reg2, %[a]}) | | | #ifdef REGVARS lil ior sil $1==$3 && $2==2 && inreg($1)==2 | regorconst | remove(referals) "or (%(regvar($1)%)),%[1]" setcc({ind_reg2, regvar($1)}) | | | #endif lil ior sil $1==$3 && $2==2 | regorconstnoaddr | allocate(ADDREG={LOCAL2, $1, 2}) remove(referals) "or (%[a]),%[1]" setcc({ind_reg2, %[a]}) | | | #ifdef REGVARS lil com sil $1==$3 && $2==2 && inreg($1)==2 | | remove(referals) "not (%(regvar($1)%))" samecc | | | #endif lil com sil $1==$3 && $2==2 | | allocate(ADDREG={LOCAL2, $1, 2}) remove(referals) "not (%[a])" samecc | | | loe adi ste $1==$3 && $2==2 | regorconst | remove(indirects) "add ($1),%[1]" setcc({EXTERN2, $1}) | | | lde adi sde $1==$3 && $2==4 | regorconst regorconst | remove(indirects) "add ($1),%[1]" "adc ($1+2),%[2]" | | | loe ngi ste $1==$3 && $2==2 | | remove(indirects) "neg ($1)" setcc({EXTERN2, $1}) | | | lde ngi sde $1==$3 && $2==4 | | remove(indirects) "neg ($1)" "neg ($1+2)" "sbb ($1+2),0" | | | loe ads ste $1==$3 && $2==2 | regorconst | remove(indirects) "add ($1),%[1]" setcc({EXTERN2, $1}) | | | loe loe adp ste $1==$4 && $1==$4 | | allocate(ADDREG={EXTERN2,$1}) | %[a] | loe $1 adp $3 ste $1 | loe ine $1==$2 | | allocate(REG={EXTERN2,$1}) | %[a] | ine $1 | loe dee $1==$2 | | allocate(REG={EXTERN2,$1}) | %[a] | dee $1 | loe adp ste $1==$3 && $2==1 | | remove(indirects) "inc ($1)" setcc({EXTERN2, $1}) | | | loe adp ste $1==$3 && $2==0-1 | | remove(indirects) "dec ($1)" setcc({EXTERN2, $1}) | | | loe adp ste $1==$3 | | remove(indirects) "add ($1),$2" setcc({EXTERN2, $1}) | | | loe and ste $1==$3 && $2==2 | regorconst | remove(indirects) "and ($1),%[1]" setcc({EXTERN2, $1}) | | | loe ior ste $1==$3 && $2==2 | regorconst | remove(indirects) "or ($1),%[1]" setcc({EXTERN2, $1}) | | | loe com ste $1==$3 && $2==2 | | remove(indirects) "not ($1)" samecc | | | /**************************************** * Group 8 : Convert instructions * ****************************************/ cii | CXREG DXREG X_ACC | remove(ALL) "call .cii" erase(%[3]) | %[3] | | ciu | | | | cuu | cui | | | | cuu | cuu | CXREG DXREG X_ACC | remove(ALL) "call .cuu" erase(%[3]) | %[3] | | 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" | bx | | sar $1==2 | X_BXREG X_ACC | remove(ALL) "call .sar2" erase(%[1]) erase(%[2]) | | | sar !defined($1) | | remove(ALL) "call .isar" | | | lar $1==2 | X_BXREG X_ACC | remove(ALL) "call .lar2" erase(%[1]) erase(%[2]) | | | lar !defined($1) | | remove(ALL) "call .ilar" | | | /**************************************** * group 12 : Compare instructions * ****************************************/ cmi $1==2 | | | | 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 register rmorconst | allocate(REG = {ANYCON,0}) "cmp %[1],%[2]" "je 2f" "jb 1f" "inc %[a]" "jmp 2f" "1:\tdec %[a]\n2:" setcc(%[a]) erase(%[a]) | %[a] | |(4,4) ... | rmorconst register | allocate(REG = {ANYCON,0}) "cmp %[1],%[2]" "je 2f" "jb 1f" "inc %[a]" "jmp 2f" "1:\tdec %[a]\n2:" setcc(%[a]) erase(%[a]) | %[a] | |(4,4) ... | ACC const | allocate(REG = {ANYCON,0}) "cmp %[1],%[2]" "je 2f" "jb 1f" "inc %[a]" "jmp 2f" "1:\tdec %[a]\n2:" setcc(%[a]) erase(%[a]) | %[a] | |(3,4) ... | const ACC | allocate(REG = {ANYCON,0}) "cmp %[1],%[2]" "je 2f" "jb 1f" "inc %[a]" "jmp 2f" "1:\tdec %[a]\n2:" setcc(%[a]) erase(%[a]) | %[a] | |(3,4) tlt | rm | allocate(REG={ANYCON,0}) test(%[1]) "jge 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | tle | rm | allocate(REG={ANYCON,0}) test(%[1]) "jg 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | teq | rm | allocate(REG={ANYCON,0}) test(%[1]) "jne 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | tne | rm | allocate(REG={ANYCON,0}) test(%[1]) "je 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | tge | rm | allocate(REG={ANYCON,0}) test(%[1]) "jl 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | tgt | rm | allocate(REG={ANYCON,0}) test(%[1]) "jle 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | tlt ior $2==2 | rm X_REG | test(%[1]) "jge 1f" "or %[2],1\n1:" erase(%[2]) | %[2] | | tle ior $2==2 | rm X_REG | test(%[1]) "jg 1f" "or %[2],1\n1:" erase(%[2]) | %[2] | | teq ior $2==2 | rm X_REG | test(%[1]) "jne 1f" "or %[2],1\n1:" erase(%[2]) | %[2] | | tne ior $2==2 | rm X_REG | test(%[1]) "je 1f" "or %[2],1\n1:" erase(%[2]) | %[2] | | tge ior $2==2 | rm X_REG | test(%[1]) "jl 1f" "or %[2],1\n1:" erase(%[2]) | %[2] | | tgt ior $2==2 | rm X_REG | test(%[1]) "jle 1f" "or %[2],1\n1:" erase(%[2]) | %[2] | | cmi tlt ior $1==2 && $3==2 | regorconst rm X_REG | "cmp %[2],%[1]" "jge 1f" "or %[3],1\n1:" erase(%[3]) | %[3] | | cmi tle ior $1==2 && $3==2 | regorconst rm X_REG | "cmp %[2],%[1]" "jg 1f" "or %[3],1\n1:" erase(%[3]) | %[3] | | cmi teq ior $1==2 && $3==2 | regorconst rm X_REG | "cmp %[2],%[1]" "jne 1f" "or %[3],1\n1:" erase(%[3]) | %[3] | | cmi tne ior $1==2 && $3==2 | regorconst rm X_REG | "cmp %[2],%[1]" "je 1f" "or %[3],1\n1:" erase(%[3]) | %[3] | | cmi tge ior $1==2 && $3==2 | regorconst rm X_REG | "cmp %[2],%[1]" "jl 1f" "or %[3],1\n1:" erase(%[3]) | %[3] | | cmi tgt ior $1==2 && $3==2 | regorconst rm X_REG | "cmp %[2],%[1]" "jle 1f" "or %[3],1\n1:" erase(%[3]) | %[3] | | /* The cmp instruction has a special form for comparing a byte ( sign-extended ) to a word (e.g. a register) The "cmp ax,0" and "cmp bx,0" instructions have widely different encodings but take the same amount of time and space. Conclusion, using the special instruction for comparing constants with ax is only better when the constant is <-128 or >127. This relatively rare event wasn't worth extra entries in this table. */ cmi tlt $1==2 | regorconst rm | allocate(REG={ANYCON,0}) "cmp %[2],%[1]" "jge 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | ... | NO rm regorconst | allocate(REG={ANYCON,0}) "cmp %[1],%[2]" "jle 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | cmi tle $1==2 | regorconst rm | allocate(REG={ANYCON,0}) "cmp %[2],%[1]" "jg 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | ... | NO rm regorconst | allocate(REG={ANYCON,0}) "cmp %[1],%[2]" "jl 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | cmi teq $1==2 | regorconst rm | allocate(REG={ANYCON,0}) "cmp %[2],%[1]" "jne 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | ... | NO rm regorconst | allocate(REG={ANYCON,0}) "cmp %[1],%[2]" "jne 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | cmi tne $1==2 | regorconst rm | allocate(REG={ANYCON,0}) "cmp %[2],%[1]" "je 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | ... | NO rm regorconst | allocate(REG={ANYCON,0}) "cmp %[1],%[2]" "je 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | cmi tge $1==2 | regorconst rm | allocate(REG={ANYCON,0}) "cmp %[2],%[1]" "jl 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | ... | NO rm regorconst | allocate(REG={ANYCON,0}) "cmp %[1],%[2]" "jg 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | cmi tgt $1==2 | regorconst rm | allocate(REG={ANYCON,0}) "cmp %[2],%[1]" "jle 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | ... | NO rm regorconst | allocate(REG={ANYCON,0}) "cmp %[1],%[2]" "jge 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | cmp tlt | regorconst rm | allocate(REG={ANYCON,0}) "cmp %[2],%[1]" "jae 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | ... | NO rm regorconst | allocate(REG={ANYCON,0}) "cmp %[1],%[2]" "jbe 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | cmp tle | regorconst rm | allocate(REG={ANYCON,0}) "cmp %[2],%[1]" "ja 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | ... | NO rm regorconst | allocate(REG={ANYCON,0}) "cmp %[1],%[2]" "jb 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | cmp teq | regorconst rm | allocate(REG={ANYCON,0}) "cmp %[2],%[1]" "jne 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | ... | NO rm regorconst | allocate(REG={ANYCON,0}) "cmp %[1],%[2]" "jne 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | cmp tne | regorconst rm | allocate(REG={ANYCON,0}) "cmp %[2],%[1]" "je 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | ... | NO rm regorconst | allocate(REG={ANYCON,0}) "cmp %[1],%[2]" "je 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | cmp tge | regorconst rm | allocate(REG={ANYCON,0}) "cmp %[2],%[1]" "jb 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | ... | NO rm regorconst | allocate(REG={ANYCON,0}) "cmp %[1],%[2]" "ja 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | cmp tgt | regorconst rm | allocate(REG={ANYCON,0}) "cmp %[2],%[1]" "jbe 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | ... | NO rm regorconst | allocate(REG={ANYCON,0}) "cmp %[1],%[2]" "jae 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | cms teq $1==2 | regorconst rm | allocate(REG={ANYCON,0}) "cmp %[2],%[1]" "jne 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | ... | NO rm regorconst | allocate(REG={ANYCON,0}) "cmp %[1],%[2]" "jne 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | cms tne $1==2 | regorconst rm | allocate(REG={ANYCON,0}) "cmp %[2],%[1]" "je 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | ... | NO rm regorconst | allocate(REG={ANYCON,0}) "cmp %[1],%[2]" "je 1f" "inc %[a]\n1:" erase(%[a]) | %[a] | | cmp zlt | regorconst rm | 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 | | remove(ALL) "call .lfr6" | | | lfr $1==8 | | remove(ALL) "call .lfr8" | | | ret $1==0 | | remove(ALL) #ifdef REGVARS return #else "mov sp,bp" "pop bp" "ret" #endif | | | ret $1==2 | ACC | remove(ALL) #ifdef REGVARS return #else "mov sp,bp" "pop bp" "ret" #endif | | | ret $1==4 | ACC DXREG | remove(ALL) #ifdef REGVARS return #else "mov sp,bp" "pop bp" "ret" #endif | | | ret $1==6 | STACK | "call .ret6" #ifdef REGVARS return #else "mov sp,bp" "pop bp" "ret" #endif | | | ret $1==8 | STACK | "call .ret8" #ifdef REGVARS return #else "mov sp,bp" "pop bp" "ret" #endif | | | /************************************************ * Group 15 : Miscellaneous instructions * ************************************************/ asp $1==2 | nocoercions : a_word | | | | ... | STACK | allocate(BXREG) "pop %[a]" erase(%[a]) samecc | | | (1,8) asp $1==4 | nocoercions : a_word a_word | | | | ... | STACK | allocate(BXREG) "pop %[a]" "pop %[a]" erase(%[a]) samecc | | | (2,16) asp $1==0-2 | | /* Anything will do */ | bp | | ... | | 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 | | remove(ALL) allocate(CXREG={ANYCON,$1/2}) "call .blm" erase(%[a]) | | | bls $1==2 | X_CXREG | remove(ALL) "sar cx,1" "call .blm" erase(%[1]) | | | bls !defined($1)| rm-CXREG X_CXREG | remove(ALL) "cmp %[1],2" "jne .unknown" "sar cx,1" "call .blm" erase(%[2]) | | | csa $1==2 | X_BXREG X_ACC | remove(ALL) "jmp .csa2" erase(%[1]) erase(%[2]) | | | csa !defined($1)| rm-BXREG-ACC X_BXREG X_ACC | remove(ALL) "cmp %[1],2" "jne .unknown" "jmp .csa2" erase(%[2]) erase(%[3]) | | | csb $1==2 | X_BXREG X_ACC | remove(ALL) "jmp .csb2" erase(%[1]) erase(%[2]) | | | csb !defined($1)| rm-BXREG-ACC X_BXREG X_ACC | remove(ALL) "cmp %[1],2" "jne .unknown" "jmp .csb2" erase(%[2]) erase(%[3]) | | | dup $1==2 | regorconst | | %[1] %[1] | | ... | ACC1 | | %[1] %[1] | | dup $1==4 | regorconst regorconst | | %[2] %[1] %[2] %[1] | | dup | | remove(ALL) move({ANYCON, $1}, cx) "call .dup" erase(cx) | | | dus $1==2 | X_CXREG | remove(ALL) "call .dup" erase(%[1]) | | | dus !defined($1)| rm-CXREG X_CXREG | remove(ALL) "cmp %[1],2" "jne .unknown" "call .dup" erase(%[2]) | | | exg $1==2 | a_word a_word | | %[1] %[2] | | exg $1==4 | a_word a_word a_word a_word | | %[2] %[1] %[4] %[3] | | exg defined($1) | | remove(ALL) move({ANYCON,$1},cx) "call .exg" erase(cx) | | | exg | rmorconst | remove(ALL) move(%[1],cx) "call .exg" erase(cx) | | | gto | | remove(ALL) "mov bx,$1" "jmp .gto" | | | fil | | "mov (hol0+4),$1" | | | lim | | allocate(REG) "mov %[a],(.ignmask)" | %[a] | | lin | | "mov (hol0),$1" | | | lni | | "inc (hol0)" | | | lor $1==0 | | | bp | | lor $1==1 | | 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 | BXREG ACC | "call .rck" | ax | | rck !defined($1)| rm-BXREG-ACC BXREG ACC | "cmp %[1],2" "jne .unknown" "call .rck" | ax | | rtt | | | | ret 0 | sig | X_REG | "xchg (.trppc),%[1]" erase(%[1]) | %[1] | | sim | regorconst | "mov (.ignmask),%[1]" | | | str $1==0 | rmorconst | "mov bp,%[1]" | | | str $1==1 | rmorconst | 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] | halfindir | allocate(%[1],REG) move(%[1],%[a]) samecc | %[a] | |(0,0) | halfindir | allocate(%[1],ADDREG) move(%[1],%[a]) samecc | %[a] | |(0,0) /******************************** * From source to token * ********************************/ | ANYCON | | {ADDR_EXTERN,tostring(%[1.val])} | | /******************************** * From source1 * ********************************/ | rm1 | allocate(%[1],REG1=%[1]) | %[a] | | | rm1 | allocate(%[1],GENREG) move(%[1],%[a.1]) "xorb %[a.2],%[a.2]" | %[a] | |(2,3) | ACC1 | allocate(%[1],ACC) "xorb %[a.2],%[a.2]" | %[a] | |(2,3) /* | BLREG | allocate(%[1],BXREG) "xorb %[a.2],%[a.2]" | %[a] | |(2,3) */ /************************ * From STACK coercions * ************************/ | STACK | allocate(REG) "pop %[a]" samecc | %[a] | | (2,8) MOVES: (ACC, EXTERN2, "mov %[2],%[1]" samecc, (3,16)) (ACC1, EXTERN1, "movb %[2],%[1]" samecc, (3,16)) (ACC, EXTERN1, "movb %[2],%[1.1]" samecc, (3,16)) (EXTERN2, ACC, "mov %[2],%[1]" samecc, (3,14)) (EXTERN1, ACC1, "movb %[2],%[1]" samecc, (3,14)) (rm, register, "mov %[2],%[1]" samecc, (2,2) + %[1] ) (anyreg, dest, "mov %[2],%[1]" samecc, (2,3) + %[2] ) (halfindir, register, "lea %[2],%[1]" samecc, (2,3) + %[1] ) (rm1, REG1, "movb %[2],%[1]" samecc, (2,2) + %[1] ) (REG1, rm1, "movb %[2],%[1]" samecc, (2,3) + %[2] ) (GENREG, rm1, "movb %[2],%[1.1]" samecc, (2,3) + %[2] ) (ANYCON %[val]==0, register, "xor %[2],%[2]" setcc(%[2]), (2,3)) (ANYCON %[val]==0, REG1, "xorb %[2],%[2]" setcc(%[2]),(2,3)) (const, register, "mov %[2],%[1]" samecc, (3,4)) (const, REG1, "movb %[2],%[1]" samecc, (2,4)) (const, dest, "mov %[2],%[1]" samecc, (4,4) + %[2] ) (const, rm1, "movb %[2],%[1]" samecc, (3,4) + %[2] ) TESTS: (anyreg, "or %[1],%[1]", (2,3)) (memory2, "cmp %[1],0", (3,11)+%[1]) (REG1, "orb %[1],%[1]", (2,3)) (memory1, "cmpb %[1],0", (3,11)+%[1]) STACKS: (anyreg, , "push %[1]" samecc , (1,10) ) (memory2, , "push %[1]" samecc , (2,10) + %[1] ) (const, REG, move(%[1],%[a]) "push %[a]" samecc , (4,11) ) (const, , ".sect .data\n1: .data2 %[1]\n.sect text" "push (1b)" samecc , (6,24) ) (rm1, GENREG, move({ANYCON,0},%[a]) move(%[1],%[a.1]) "push %[a]" samecc , (2,10) + %[1] ) (rm1, , "push %[1]" "push si" "mov si,sp" "movb 3(si),0" "pop si" samecc , (10,60) + %[1] ) (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] ) (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] )