// peeph-r2k.def - Rabbit 2000 (derived from Z80 peephole rules) // // Some of these peepholes could be potentially moved to peeph.def, but a // GBZ80 expert should have a look at them before. // // (c) Philipp Klaus Krause (pkk@spth.de, philipp@colecovision.eu) 2006 - 2015 // *** modified by Leland Morrison for rabbit 2000 processor 2011 // // This program is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the // Free Software Foundation; either version 2, or (at your option) any // later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. replace restart { ld %1, %1 } by { ; peephole 0 removed redundant load from %1 into %1. } if notVolatile(%1) replace restart { ld %1, %2 } by { ; peephole 1 removed dead load from %2 into %1. } if notVolatile(%1), notUsed(%1), notVolatile(%2) replace restart { add ix,sp } by { ; peephole 2 removed dead frame pointer setup. } if notUsed('ix') replace restart { ld %1, %2 + %3 } by { ; peephole 3 removed dead load from %2 + %3 into %1. } if notVolatile(%1), notUsed(%1) // Should probably check for notVolatile(%2), too, but gives many false positives and no regression tests fail. replace restart { ld %1, (iy) } by { ld %1, 0 (iy) ; peephole 4 made 0 offset explicit. } replace restart { ld (iy), %1 } by { ld 0 (iy), %1 ; peephole 5 made 0 offset explicit. } replace restart { inc hl } by { ; peephole 5a removed dead increment of hl. } if notUsed('hl') replace restart { dec hl } by { ; peephole 6 removed dead decrement of hl. } if notUsed('hl') replace restart { ld %1, %2 (iy) } by { ; peephole 7 removed dead load from %2 (iy) into %1. } if notUsed(%1) // Should probably check for notVolatile(), but gives many false positives and no regression tests fail. replace restart { ld %1, %2 (ix) } by { ; peephole 8 removed dead load from %2 (ix) into %1. } if notUsed(%1) replace restart { ld %1, %2 ld %3, %1 } by { ; peephole 9 loaded %3 from %2 directly instead of going through %1. ld %3, %2 } if canAssign(%3 %2), notVolatile(%1), notUsed(%1) replace restart { ld %1, hl ld hl, %1 } by { ; peephole 9a reused value still in hl. ld %1, hl } if notVolatile(%1) replace restart { ld %1, %2 ld %3, %4 ld %5, %1 } by { ld %5, %2 ; peephole 10 loaded %5 from %2 directly instead of going through %1. ld %3, %4 } if canAssign(%5 %2), notVolatile(%1), operandsNotRelated(%1 %4), operandsNotRelated(%1 %3), operandsNotRelated(%3 %5), operandsNotRelated(%4 %5), notUsed(%1), notSame(%3 %4 '(hl)' '(de)' '(bc)'), notVolatile(%5) // Rule OK unless both %5 and %4 are volatile, but we can't express that directly. replace restart { ld %1, %2 (%3) ld %4, %1 } by { ; peephole 11 loaded %2 (%3) into %4 directly instead of going through %1. ld %4, %2 (%3) } if canAssign(%4 %2 %3), notVolatile(%1), notUsed(%1) replace restart { ld %1, %2 ld %3 (%4), %1 } by { ; peephole 12 loaded %2 into %3 (%4) directly instead of going through %1. ld %3 (%4), %2 } if canAssign(%3 %4 %2), notVolatile(%1), notUsed(%1), notSame(%1 'hl') replace restart { ld %1, %2 (%3) ld %4, %5 (%6) ld %7, %1 } by { ld %7, %2 (%3) ; peephole 13 loaded %2 (%3) into %7 directly instead of going through %1. ld %4, %5 (%6) } if canAssign(%7 %2 %3), notVolatile(%1), notUsed(%1), notSame(%1 %4), notSame(%7 %4) replace restart { ld %1, %7 ld %5 (%6), %4 ld %2 (%3), %1 } by { ld %5 (%6), %4 ; peephole 14 loaded %7 into %2 (%3) directly instead of going through %1. ld %2 (%3), %7 } if canAssign(%2 %3 %7), notVolatile(%1), notUsed(%1), notSame(%1 %4 %1 'hl') replace restart { ld %1, %2 (%3) ld %4, %5 ld %7, %1 } by { ld %7, %2 (%3) ; peephole 15 loaded %2 (%3) into %7 directly instead of going through %1. ld %4, %5 } if canAssign(%7 %2 %3), notVolatile(%1), notUsed(%1), operandsNotRelated(%1 %5), operandsNotRelated(%7 %4), operandsNotRelated(%7 %5), notSame(%4 '(hl)' '(de)' '(bc)'), notSame(%5 '(hl)' '(de)' '(bc)' '(iy)') replace restart { ld %1,#%2 ld a,%3 (%1) } by { ; peephole 16 loaded %2 into a directly instead of going through %1. ld a,(#%2 + %3) } if notUsed(%1) replace restart { ld hl,#%1 ld a,(hl) } by { ld a,(#%1) ; peephole 17 loaded a from (#%1) directly instead of using hl. } if notUsed('hl') replace restart { ld hl,#%1 + %2 ld a,(hl) } by { ; peephole 18 loaded %2 into a directly instead of using hl. ld a,(#%1 + %2) } if notUsed('hl') replace restart { ld hl,#%1 ld (hl),a } by { ld (#%1),a ; peephole 19 loaded (#%1) from a directly instead of using hl. } if notUsed('hl') replace restart { ld hl,#%1 + %2 ld (hl),a } by { ld (#%1 + %2),a ; peephole 20 loaded (#%1) from a directly instead of using hl. } if notUsed('hl') replace restart { srl %1 ld a,%1 } by { ld a,%1 ; peephole 21 shifted in a instead of %1. srl a } if notVolatile(%1), notUsed(%1) replace restart { ld e, l ld d, h ld a, (de) srl a ld (de), a } by { ld e, l ld d, h srl (hl) ; peephole 21a shifted in (hl) instead of a. } if notUsed('a') replace restart { ld iy, #%1 ld %2, %3 (iy) srl %2 bit %4, %3 (iy) } by { ld hl, #%1 + %3 ; peephole 21c used hl instead of iy. ld %2, (hl) srl %2 bit %4, (hl) } if notUsed('iy'), notUsed('hl') replace restart { ld %1,(hl) ld a,%2 (%3) sub a,%1 } by { ld a,%2 (%3) ; peephole 22 used (hl) in sub directly instead of going through %1. sub a,(hl) } if notVolatile(%1), notUsed(%1) replace restart { inc bc ld l,c ld h,b } by { ld l,c ld h,b ; peephole 23 incremented in hl instead of bc. inc hl } if notUsed('bc') replace restart { inc de ld l,e ld h,d } by { ld l,e ld h,d ; peephole 24 incremented in hl instead of de. inc hl } if notUsed('de') replace restart { ld c,l ld b,h ld a,#%1 ld (bc),a } by { ld c,l ld b,h ld (hl),#%1 ; peephole 25 loaded #%1 into (hl) instead of (bc). } if notUsed('a') replace restart { ex de, hl push de } by { ; peephole 26 pushed hl directly instead of going through de. push hl } if notUsed('de'), notUsed('hl') replace restart { ld l,%1 ld h,d push hl } by { ; peephole 27 pushed de instead of hl removing a load. ld e,%1 push de } if notUsed('hl'), notUsed('e') replace restart { ex de, hl push bc push de } by { ; peephole 28 pushed hl directly instead of going through de. push bc push hl } if notUsed('de'), notUsed('hl') replace restart { ld l,c ld h,b push hl } by { ; peephole 29 pushed bc directly instead of going through hl. push bc } if notUsed('hl') replace restart { ld l,%1 ld h,b push hl } by { ; peephole 30 pushed bc instead of hl removing a load. ld c,%1 push bc } if notUsed('hl'), notUsed('c') replace restart { ld c,l ld b,h push %1 push bc } by { ; peephole 31 pushed hl directly instead of going through bc. push %1 push hl } if notUsed('bc'), notSame(%1 'bc') replace restart { pop de ld l, e ld h, d } by { ; peephole 32 popped hl directly instead of going through de. pop hl } if notUsed('de') replace restart { pop bc ld l, c ld h, b } by { ; peephole 33 popped hl directly instead of going through bc. pop hl } if notUsed('bc') replace restart { ld %1 (ix), %2 ld %3, %1 (ix) } by { ; peephole 34 loaded %3 from %2 instead of going through %1 (ix). ld %1 (ix), %2 ld %3, %2 } if canAssign(%3 %2) // Don't need to check for volatile, since ix is used for the stack. replace restart { ld %1 (ix), a push de ld %2, %1 (ix) } by { ld %1 (ix), a push de ; peephole 34a loaded %2 from a instead of %1 (ix) ld %2, a } if canAssign(%2 'a') replace restart { push af inc sp ld a,e push af inc sp } by { ; peephole 35 pushed de instead of pushing a twice. ld d,a push de } if notUsed('d'), notUsed('a') replace restart { push af inc sp ld a,#%1 push af inc sp } by { ; peephole 36 pushed de instead of pushing a twice. ld d,a ld e,#%1 push de } if notUsed('de') replace restart { push af inc sp ld a,#%1 push af inc sp } by { ; peephole 37 pushed bc instead of pushing a twice. ld b,a ld c,#%1 push bc } if notUsed('bc') replace restart { push bc inc sp push de inc sp } by { ld c, d ; peephole 37a combined pushing of b and d. push bc } if notUsed('c') replace restart { push bc inc sp ld a, c push af inc sp } by { push bc ld a, c ; peephole 38 simplified pushing bc. } replace restart { push de inc sp ld a, #%1 push af inc sp } by { ld e, #%1 push de ; peephole 39 simplified pushing de. } if notUsed('e') replace restart { ld a,#%1 ld d,a } by { ; peephole 40 loaded #%1 into d directly instead of going through a. ld d,#%1 } if notUsed('a') replace restart { ld %1,a ld %2,%1 } by { ; peephole 41 loaded %2 from a directly instead of going through %1. ld %2,a } if notUsed(%1) replace restart { ld a,%1 (ix) push af inc sp ld a,%2 (ix) push af inc sp } by { ; peephole 42 pushed %1 (ix), %2(ix) through hl instead of af. ld h,%1 (ix) ld l,%2 (ix) push hl } if notUsed('a'), notUsed('hl') replace restart { ld c, l ld b, h push bc } by { ; peephole 43 pushed hl instead of bc. push hl } if notUsed('bc') replace restart { pop %1 push %1 } by { ; peephole 44 eleminated dead pop/push pair. } if notUsed(%1) replace restart { ld iy,#%1 or a,%2 (iy) } by { ; peephole 45 used hl instead of iy. ld hl,#%1 + %2 or a,(hl) } if notUsed('iy'), notUsed('hl') replace restart { ld iy,#%1 ld %2,%3 (iy) } by { ; peephole 46 used hl instead of iy. ld hl,#%1 + %3 ld %2, (hl) } if notUsed('iy'), notUsed('hl') replace restart { ld iy,#%1 ld h,%3 (iy) } by { ; peephole 46a used hl instead of iy. ld hl,#%1 + %3 ld h, (hl) } if notUsed('iy'), notUsed('l') replace restart { ld iy,#%1 ld %2 (iy), %3 } by { ; peephole 46b used hl instead of iy. ld hl,#%1 + %2 ld (hl), %3 } if notUsed('iy'), notUsed('hl'), notSame(%3 'h' 'l') replace restart { ld iy,#%1 ld %2,0 (iy) ld %3,1 (iy) } by { ; peephole 47 used hl instead of iy. ld hl,#%1 ld %2, (hl) inc hl ld %3, (hl) } if notUsed('iy'), notUsed('hl'), operandsNotRelated(%2 'hl') replace restart { ld iy,#%1 ld %2 (iy),%3 ld l,%2 (iy) } by { ; peephole 48 used hl instead of iy. ld hl,#%1 + %2 ld (hl),%3 ld l,(hl) } if notUsed('iy'), notUsed('h') replace restart { ld iy,#%1 ld %2 (%3), %4 } by { ; peephole 49 used hl instead of iy. ld hl,#%1 + %2 ld (hl), %4 } if notUsed('iy'), notUsed('hl'), operandsNotRelated(%4 'hl') replace restart { ld iy,#%1 bit %2,%3 (iy) } by { ; peephole 49a used hl instead of iy. ld hl,#%1+%3 bit %2, (hl) } if notUsed('iy'), notUsed('hl') replace restart { ld iy, #%1 add iy, sp ld %2, %3 (iy) } by { ; peephole 49b used hl instead of iy. ld hl, #%1+%3 add hl, sp ld %2, (hl) } if notUsed('iy'), notUsed('hl') replace restart { ld iy, #%1 add iy, sp ld %2, 0 (iy) ld %3, 1 (iy) } by { ; peephole 49c used hl instead of iy. ld hl, #%1 add hl, sp ld %2, (hl) inc hl ld %3, (hl) } if notUsed('iy'), notUsed('hl') replace restart { ld iy, #%1 add iy, sp ld l, 0 (iy) ld h, 1 (iy) } by { ; peephole 49d used hl instead of iy. ld hl, #%1 add hl, sp ld a, (hl) inc hl ld h, (hl) ld l, a } if notUsed('iy'), notUsed('a') replace restart { ld iy, #%1 add iy, sp ld 0 (iy), #%2 ld 1 (iy), #%3 } by { ; peephole 49e used hl instead of iy. ld hl, #%1 add hl, sp ld (hl), #%2 inc hl ld (hl), #%3 } if notUsed('iy'), notUsed('hl') replace restart { ld iy, #%1 ld a, 1 (iy) or a, 0 (iy) } by { ld hl, #%1 ld a, (hl) inc hl or a, (hl) ; peephole 49f used hl instead of iy. } if notUsed('iy'), notUsed('hl') replace restart { ld iy, #%1 add iy, sp ld a, 1 (iy) or a, 0 (iy) } by { ld hl, #%1 add hl, sp ld a, (hl) inc hl or a, (hl) ; peephole 49f' used hl instead of iy. } if notUsed('iy'), notUsed('hl') replace restart { ld iy, #%1 add iy, sp bit %2, %3 (iy) } by { ld hl, #%1+%3 add hl, sp bit %2, (hl) ; peephole 49g used hl instead of iy. } if notUsed('iy'), notUsed('hl') replace restart { ld iy, #%1 add iy, sp or a, %2 (iy) } by { ld hl, #%1+%2 add hl, sp or a, (hl) ; peephole 49h used hl instead of iy. } if notUsed('iy'), notUsed('hl') replace restart { ld %1,(hl) or a,%1 } by { or a,(hl) ; peephole 50 used (hl) directly instead of going through %1. } if notUsed(%1), notSame(%1 'a') replace restart { ld c,l ld b,h inc bc } by { ; peephole 51 incremented in hl instead of bc. inc hl ld c,l ld b,h } if notUsed('hl') replace restart { ld a,%1 (%2) bit %3,a } by { ; peephole 52 tested bit of %1 (%2) directly instead of going through a. bit %3,%1 (%2) } if notUsed('a') replace restart { ld a,%1 bit %2,a } by { ; peephole 53 tested bit %2 of %1 directly instead of going through a. bit %2,%1 } if notUsed('a'), canAssign(%1 'b') replace restart { ld a, %1 set %2, a ld %1, a } by { ; peephole 54 set bit %2 of %1 directly instead of going through a. set %2, %1 ld a, %1 } if canAssign(%1 'b') // canAssign(%1 'b') is true, iff set b, %1 is possible. replace restart { ld a, %1 (%2) set %3, a ld %1 (%2), a } by { ; peephole 55 set bit %3 of %1 (%2) directly instead of going through a. set %3, %1 (%2) ld a, %1 (%2) } replace restart { ld a, %1 res %2, a ld %1, a } by { ; peephole 56 reset bit %2 of %1 directly instead of going through a. res %2, %1 ld a, %1 } if canAssign(%1 'b') // canAssign(%1 'b') is true, iff set b, %1 is possible. replace restart { ld a, %1 (%2) res %3, a ld %1 (%2), a } by { ; peephole 57 reset bit %3 of %1 (%2) directly instead of going through a. res %3, %1 (%2) ld a, %1 (%2) } replace restart { ld c, %1 (%2) ld b, %3 (%4) ld l,c ld h,b } by { ; peephole 58 stored %1 (%2) %3 (%4) into hl directly instead of going through bc. ld l, %1 (%2) ld h, %3 (%4) } if notUsed('bc') replace restart { ld c, %1 ld b, %2 ld l,c ld h,b } by { ; peephole 59 stored %2%1 into hl directly instead of going through bc. ld l, %1 ld h, %2 } if notUsed('bc'), operandsNotRelated(%2 'l') replace restart { jp NC,%1 jp %2 %1: } by { jp C,%2 ; peephole 60 removed jp by using inverse jump logic %1: } if labelRefCountChange(%1 -1) replace restart { jp C,%1 jp %2 %1: } by { jp NC,%2 ; peephole 61 removed jp by using inverse jump logic %1: } if labelRefCountChange(%1 -1) replace restart { jp NZ,%1 jp %2 %1: } by { jp Z,%2 ; peephole 62 removed jp by using inverse jump logic %1: } if labelRefCountChange(%1 -1) replace restart { jp Z,%1 jp %2 %1: } by { jp NZ,%2 ; peephole 63 removed jp by using inverse jump logic %1: } if labelRefCountChange(%1 -1) replace restart { jp %5 } by { jp %6 ; peephole 64 jumped to %6 directly instead of via %5. } if labelIsUncondJump(), notSame(%5 %6), labelRefCountChange(%5 -1), labelRefCountChange(%6 +1) replace restart { jp %1,%5 } by { jp %1,%6 ; peephole 65 jumped to %6 directly instead of via %5. } if labelIsUncondJump(), notSame(%5 %6), labelRefCountChange(%5 -1), labelRefCountChange(%6 +1) replace restart { jp %1 %2: %1: } by { ; peephole 65a eliminated jump. %2: %1: } if labelRefCountChange(%1 -1) // A peephole that makes the code longer. Let's hope it's worth it in speed gain and further optimization potential. replace restart { ld a,#0x00 %1: bit %2,a jp Z,%3 } by { ld a,#0x00 jp %3 ; peephole 65a jumped directly to %3 instead of testing a first. %1: bit %2,a jp Z,%3 } if labelRefCountChange(%3 +1) replace restart { ld %1, %2 jp %3 jp %4 } by { ld %1, %2 jp %3 ; peephole 65b removed unreachable jump to %3. } replace restart { ld %1, %2 jp %3 %3: } by { ld %1, %2 %3: ; peephole 65c removed redundant jump to %3. } if labelRefCountChange(%3 -1) replace restart { ld %1, #0x01 bit 0, %1 jp Z, %2 } by { ld %1, #0x01 ; peephole 65d removed impossible jump to %2. } if labelRefCountChange(%2 -1) replace restart { xor a,a ld a,#0x00 } by { xor a,a ; peephole 66 removed redundant load of 0 into a. } replace { ld e,#0x%1 ld d,#0x%2 } by { ld de,#0x%2%1 ; peephole 67 combined constant loads into register pair. } replace { ld l,#0x%1 ld h,#0x%2 } by { ld hl,#0x%2%1 ; peephole 68 combined constant loads into register pair. } replace { ld c,#0x%1 ld b,#0x%2 } by { ld bc,#0x%2%1 ; peephole 69 combined constant loads into register pair. } replace restart { ld %1,a ld a,%1 } by { ld %1,a ; peephole 70 removed redundant load from %1 into a. } if notVolatile(%1) // This gives many false negatives and without the test no problems are encountered in the regression tests // Maybe we can try this after 2.7.0 release replace restart { ld a,%1 ld %1,a } by { ld a,%1 ; peephole 71 removed redundant load from a into %1. } if notVolatile(%1) // This gives many false negatives and without the test no problems are encountered in the regression tests // Maybe we can try this after 2.7.0 release replace restart { ld %2 (ix), %1 ld %1, %2 (ix) } by { ld %2 (ix), %1 ; peephole 71a removed redundant load of %1 from %2 (ix) } replace restart { ld %1,a ld a,%2 or a,%1 } by { ld %1,a or a,%2 ; peephole 72 removed load by reordering or arguments. } if notVolatile(%1), canAssign('b' %2) // canAssign('b' %2) is true, iff or a,%2 is possible. replace restart { or a,%1 or a,a } by { or a,%1 ; peephole 73 removed redundant or after or. } replace restart { or a,%1 (%2) or a,a } by { or a,%1 (%2) ; peephole 74 removed redundant or after or. } replace restart { and a,%1 or a,a } by { and a,%1 ; peephole 75 removed redundant or after and. } replace restart { xor a,%1 or a,a } by { xor a,%1 ; peephole 76 removed redundant or after xor. } replace restart { xor a,%1 (%2) or a,a } by { xor a,%1 (%2) ; peephole 77 removed redundant or after xor. } replace { ld %1,%2 ld a,%2 } by { ld a,%2 ld %1,a ; peephole 78 load value in a first and use it next } if notVolatile(%1 %2) replace restart { ld %1,%2 ld %3,%4 ld %2,%1 ld %4,%3 } by { ld %1,%2 ld %3,%4 ; peephole 79 removed redundant load from %3%1 into %4%2 } if notVolatile(%1 %2 %3 %4) replace restart { push de inc sp ld a,e push af inc sp } by { push de ; peephole 80 pushed de } if notUsed('a') replace restart { ld iy,%1 add iy,sp ld sp,iy } by { ld hl,%1 add hl,sp ld sp,hl ; peephole 81 fixed stack using hl instead of iy. } if notUsed('hl'), notUsed('iy') replace restart { ld a,%1 sub a,%2 jp %3,%4 ld a,%1 } by { ld a,%1 cp a,%2 jp %3,%4 ; peephole 82 removed load by replacing sub with cp assert a=%1 } if notVolatile(%1), notUsedFrom(%4 'a') replace restart { assert a=%1 sub a,%2 jp %3,%4 ld a,%1 } by { cp a,%2 jp %3,%4 ; peephole 83 removed load by replacing sub with cp assert a=%1 } if notUsedFrom(%4 'a') replace restart { assert a=%1 } by { } replace restart { sub a,#0xFF jp Z,%1 } by { inc a ; peephole 84 replaced sub a,#0xFF by inc a. jp Z,%1 } replace restart { sub a,#0xFF jp NZ,%1 } by { inc a ; peephole 85 replaced sub a,#0xFF by inc a. jp NZ,%1 } replace restart { rlca ld a,#0x00 rla } by { rlca and a,#0x01 ; peephole 86 replaced zero load, rla by and since rlca writes the same value to carry bit and least significant bit. } replace restart { ld %1,%2 push %1 pop %4 ld %1,%3 } by { ld %4,%2 ; peephole 87 moved %2 directly into de instead of going through %1. ld %1,%3 } replace restart { add a,#0x00 ld %2,a ld a,%3 adc a,%4 } by { ; peephole 88 removed lower part of multibyte addition. ld %2,a ld a,%3 add a,%4 } replace restart { ld a, l add a, #0x%1 ld e, a ld a, h adc a, #0x%2 ld d, a } by { ld de, #0x%2%1 add hl, de ; peephole 89 used 16-bit addition. ld e, l ld d, h ld a, h } if notUsed('hl') replace restart { ld a, l add a, #0x%1 ld c, a ld a, h adc a, #0x%2 ld b, a } by { ld bc, #0x%2%1 add hl,bc ; peephole 90 used 16-bit addition. ld c, l ld b, h ld a, h } if notUsed('hl') replace restart { ld %1,a ld a,%2 add a,%1 } by { ; peephole 91 removed loads by exploiting commutativity of addition. add a,%2 } if notVolatile(%1), notUsed(%1), canAssign('b' %2) // canAssign('b' %2) is true, iff add a,%2 is possible. replace restart { ld %1 (ix),a ld a,#%2 add a,%1 (ix) } by { ld %1 (ix),a ; peephole 92 removed loads by exploiting commutativity of addition. add a,#%2 } // Don't need to check for volatile, since ix is used to access the stack. replace restart { ld l,%1 (ix) ld h,%2 (ix) ld a,(hl) inc a ld l,%1 (ix) ld h,%2 (ix) ld (hl),a } by { ld l,%1 (ix) ld h,%2 (ix) inc (hl) ; peephole 93 incremented in (hl) instead of going through a. } if notUsed('a') replace restart { ld %1, %2 (%3) inc %1 ld %2 (%3), %1 } by { inc %2 (%3) ld %1, %2 (%3) ; peephole 93a incremented in %2 (%3) instead of going through %1. } if notSame(%3 'sp') replace restart { ld %1,a ld a,%2 add a,%1 } by { ld %1, a ; peephole 94 removed load by exploiting commutativity of addition. add a,%2 } if notSame(%2 '(bc)' '(de)'), canAssign('b' %2) // canAssign('b' %2) is true, iff add a,%2 is possible. replace restart { ld c,l ld b,h ld hl,#%1 add hl,bc } by { ; peephole 95 removed loads by exploiting commutativity of addition. ld bc,#%1 add hl,bc } if notUsed('bc') replace restart { ld hl,#%1 add hl,%2 ld bc,#%4 add hl,bc } by { ; peephole 96 removed loads by exploiting commutativity of addition. ld hl,#%1 + %4 add hl,%2 } if notUsed('bc') replace restart { ld c,e ld b,d ld hl,#%1 add hl,bc } by { ; peephole 97 removed loads by exploiting commutativity of addition. ld hl,#%1 add hl,de } if notUsed('bc') replace restart { or a,%1 jp NZ,%2 ld %3,#0x00 } by { or a,%1 jp NZ,%2 ld %3,a ; peephole 98 replaced constant #0x00 by a (which has just been tested to be #0x00). } replace restart { and a,%1 jp NZ,%2 ld %3,#0x00 } by { and a,%1 jp NZ,%2 ld %3,a ; peephole 99 replaced constant #0x00 by a (which has just been tested to be #0x00). } replace restart { sub a,%1 jp NZ,%2 ld %3,#0x00 } by { sub a,%1 jp NZ,%2 ld %3,a ; peephole 100 replaced constant #0x00 by a (which has just been tested to be #0x00). } replace restart { inc a jp NZ,%1 ld %2,#0x00 } by { inc a jp NZ,%1 ld %2,a ; peephole 101 replaced constant #0x00 by a (which has just been tested to be #0x00). } replace restart { dec a jp NZ,%1 ld %2,#0x00 } by { dec a jp NZ,%1 ld %2,a ; peephole 102 replaced constant #0x00 by a (which has just been tested to be #0x00). } replace restart { or a,%1 jp NZ,%2 ld a,%3 or a,a } by { or a,%1 jp NZ,%2 or a,%3 ; peephole 103 shortened or using a (which has just been tested to be #0x00). } if canAssign('b' %3) // canAssign('b' %2) is true, iff or a,%2 is possible. replace restart { sub a,%1 jp NZ,%2 ld a,%3 or a,a } by { sub a,%1 jp NZ,%2 or a,%3 ; peephole 104 shortened or using a (which has just been tested to be #0x00). } if canAssign('b' %3) // canAssign('b' %2) is true, iff or a,%2 is possible. replace restart { or a,%1 jp NZ,%2 push %3 ld %4,#0x00 } by { or a,%1 jp NZ,%2 push %3 ld %4,a ; peephole 105 replaced constant #0x00 by a (which has just been tested to be #0x00). } replace restart { ld hl,#%1 add hl,%2 inc hl } by { ld hl,#%1+1 add hl,%2 ; peephole 107 moved increment of hl to constant. } replace restart { inc hl ld %1,#%2 add hl,%1 } by { ld %1,#%2+1 add hl,%1 ; peephole 108 moved increment of hl to constant. } if notUsed(%1) replace restart { dec hl ld %1,#%2 add hl,%1 } by { ld %1,#%2-1 add hl,%1 ; peephole 109 moved decrement of hl to constant. } if notUsed(%1) replace restart { inc hl inc hl inc hl ld hl, (hl) } by { ; peephole 109a moved increment of hl to offset. ld hl, 3 (hl) } replace restart { inc hl inc hl ld hl, (hl) } by { ; peephole 109b moved increment of hl to offset. ld hl, 2 (hl) } replace restart { inc hl ld hl, (hl) } by { ; peephole 109c moved increment of hl to offset. ld hl, 1 (hl) } replace restart { inc iy ld %1, %2 (iy) } by { ld %1, %2+1 (iy) ; peephole 110 moved increment of iy to offset. } if notUsed('iy') replace restart { push hl pop iy pop hl inc iy } by { inc hl push hl pop iy pop hl ; peephole 111 incremented in hl instead of iy. } replace restart { push hl pop iy inc iy } by { inc hl push hl pop iy ; peephole 111a incremented in hl instead of iy. } if notUsed('hl') replace restart { push bc pop iy inc iy } by { inc bc push bc pop iy ; peephole 111b incremented in bc instead of iy. } if notUsed('bc') replace restart { push de pop iy inc iy } by { inc de push de pop iy ; peephole 111c incremented in de instead of iy. } if notUsed('de') replace restart { ld hl,%1 add hl,%2 push hl pop iy } by { ld iy,%1 add iy,%2 ; peephole 111b added in iy instead of hl. } if notUsed('hl'), notSame(%2 'hl') replace restart { pop af ld sp,%1 } by { ; peephole 112 removed redundant pop af. ld sp,%1 } if notUsed('a') replace restart { inc sp ld sp,%1 } by { ; peephole 113 removed redundant inc sp. ld sp,%1 } if notUsed('a') replace restart { call %1 ret } by { jp %1 ; peephole 114 replaced call at end of function by jump (tail call optimization). } if symmParmStack(%1) // Callee saves ix. replace restart { call %1 pop ix ret } by { pop ix jp %1 ; peephole115 replaced call at end of function by jump moving call beyond pop ix (tail call optimization). } if symmParmStack(%1) replace restart { ld %1,#%2 ld %3,%4 ld %1,#%2 } by { ld %1,#%2 ld %3,%4 ; peephole 116 removed load of #%2 into %1 since it's still there. } if notVolatile(%1), operandsNotRelated(%3 %1) replace restart { ld hl,#%1 ld de,#%1 } by { ; peephole 117 used #%1 from hl for load into de. ld hl,#%1 ld e,l ld d,h } replace restart { ld %1 (ix),l ld %2 (ix),h ld %3,%1 (ix) ld %4,%2 (ix) } by { ld %1 (ix),l ld %2 (ix),h ; peephole 118 used hl instead of %2 (ix), %1 (ix) to load %4%3. ld %3,l ld %4,h } if operandsNotRelated('h' %3) // Don't check for volatile since ix points to the stack. replace restart { ld %1, a ld a, %2 (%3) adc a, #%4 ld %6, %1 } by { ld %6, a ld a, %2 (%3) adc a, #%4 ; peephole 119 loaded %6 from a directly instead of going through %1. } if notUsed(%1) replace restart { ld %1, a ld a, %2 (%3) adc a, #%4 ld %5, a ld %6, %1 } by { ld %6, a ld a, %2 (%3) adc a, #%4 ld %5, a ; peephole 120 loaded %6 from a directly instead of going through %1. } if notUsed(%1), notSame(%5 %1), notSame(%5 '(hl)' '(de)' '(bc)'), notSame(%5 %6), notSame(%6 '(hl)' '(de)' '(bc)'), notSame(%5 'a'), notSame(%6 'a') replace restart { ld %1, a ld a, #%2 adc a, #%3 ld %5, a ld %6, %1 } by { ld %6, a ld a, #%2 adc a, #%3 ld %5, a ; peephole 121 loaded %6 from a directly instead of going through %1. } if notUsed(%1), notSame(%5 %1), notSame(%5 %6 '(hl)' '(de)' '(bc)'), notSame(%6 'a') replace restart { ld hl, #%1 add hl, %2 ex de, hl ld hl, #%3 add hl, de } by { ld hl, #%1+%3 add hl, %2 ; peephole 122 removed addition and loads exploiting commutativity of addition. } if notUsed('de') replace restart { ld %1,l ld %2,h ex de,hl ld (hl),%1 inc hl ld (hl),%2 } by { ld %1,l ex de,hl ; peephole 122a used de instead of going through %1%2. ld (hl),e inc hl ld (hl),d } if notUsed(%2), notSame(%1 'l' 'h' 'e' 'd'), notSame(%2 'l' 'h' 'e' 'd') replace restart { ld e, l ld d, h ld hl, #0x0001 add hl, de } by { ld e, l ld d, h inc hl ; peephole 123 replaced addition by increment. } replace restart { ld sp,hl ld hl,#0x0002 add hl,sp } by { ld sp, hl inc hl inc hl ; peephole 124 replaced addition by increment. } replace restart { ex de, hl ld hl, #%1 add hl, de } by { ; peephole 125 removed ex exploiting commutativity of addition. ld de, #%1 add hl, de } if notUsed('de') replace restart { ex de, hl push bc ex de, hl } by { push bc ; peephole 126 canceled subsequent ex de, hl. } replace restart { ld hl, #%1 add hl, %2 ex de, hl inc de } by { ld hl, #%1+1 ; peephole 127 moved increment to constant. add hl, %2 ex de, hl } if notUsed('hl') replace restart { ld a,#0x01 jp %1 %2: xor a,a %1: sub a,#0x01 ld a,#0x00 rla } by { xor a,a jp %1 %2: ld a,#0x01 %1: ; peephole 128 removed negation. } if labelRefCount(%1 1) replace restart { and a,#0x01 sub a,#0x01 ld a,#0x00 rla } by { and a,#0x01 xor a,#0x01 ; peephole 129 used xor for negation. } replace restart { or a,a sub a,#%1 } by { ; peephole 130 removed redundant or. sub a,#%1 } replace restart { ld a,#0x00 rla sub a,#0x01 ld a,#0x00 rla } by { ld a,#0x00 ccf ; peephole 131 moved negation from bit 0 to carry flag. rla } replace restart { ld a, #<(%1) add a, l ld l, a ld a, #>(%1) adc a, h ld h, a push bc } by { push bc ld bc, #%1 add hl, bc ; peephole 132 used 16 bit addition by moving push bc ld a, h } if notUsed('bc') replace restart { pop af push hl } by { ; peephole 133 used ex to move hl onto the stack. ld 0(sp),hl } if notUsed('a'), notUsed('hl') replace restart { pop af ld hl, #%1 push hl } by { ld hl, #%1 ; peephole 134 used 0(sp) to move hl onto the stack. ld 0(sp),hl } if notUsed('a'), notUsed('hl') replace restart { pop af inc sp ld hl,#%1 push hl } by { inc sp ld hl,#%1 ; peephole 135 used 0(sp) to move #%1 onto the stack. ld 0(sp),hl } if notUsed('a'), notUsed('hl') replace restart { pop af ld a,#%1 push af inc sp } by { ld h,#%1 ld 0(sp),hl ; peephole 136 used 0(sp) to move #%1 onto the stack. inc sp } if notUsed('a'), notUsed('hl') replace restart { ld %1,#%2 ld %3 (%1),a %4: ld %1,%5 } by { ld (#%2 + %3),a ; peephole 137 directly used #%2 instead of going through %1 using indirect addressing. %4: ld %1,%5 } replace restart { pop af ld %1,#%2 ld %3 (%1),%4 ld %1,#%5 } by { ld a,%4 ld (#%2 + %3),a ; peephole 138 used #%2 directly instead of going through %1 using indirect addressing. pop af ld %1,#%5 } if notSame(%3 'a') replace restart { ld %1,a bit %2,%1 } by { bit %2,a ; peephole 139 tested bit %2 of a directly instead of going through %1. } if notUsed(%1) replace restart { sbc a,%1 bit 7,a jp Z,%2 } by { sbc a,%1 jp P,%2 ; peephole 140 used sign flag instead of testing bit 7. } replace restart { sbc a,%1 bit 7,a jp NZ,%2 } by { sbc a,%1 jp M,%2 ; peephole 141 used sign flag instead of testing bit 7. } replace restart { dec %1 ld a, %1 or a, a } by { dec %1 ; peephole 141a removed redundant transfer and flag setting in a } if notUsed('a') replace restart { ld %1,a or a,a jp %3,%4 ld a,%1 } by { ld %1,a or a,a jp %3,%4 ; peephole 142 used value still in a instead of reloading from %1. } replace { jp %5 ret } by { jp %5 ; peephole 143 removed unused ret. } replace { jp %5 ld sp,ix pop ix ret } by { jp %5 ; peephole 144 removed unused ret. } replace restart { or a,%1 jp NZ,%2 xor a,a jp %3 } by { or a,%1 jp NZ,%2 ; peephole 145 removed redundant zeroing of a (which has just been tested to be #0x00). jp %3 } replace restart { dec hl inc hl } by { ; peephole 145a removed inc hl / dec hl pair. } replace restart { jp Z, %2 ld a, #%3 jp %1 %2: ld a, #%4 %1: } by { ld a, #%3 jp NZ, %1 %2: ld a, #%4 ; peephole 168z used double assignment in case of Z condition. %1: } if labelRefCountChange(%2 -1) replace restart { jp NZ, %2 ld a, #%3 jp %1 %2: ld a, #%4 %1: } by { ld a, #%3 jp Z, %1 %2: ld a, #%4 ; peephole 168nz used double assignment in case of NZ condition. %1: } if labelRefCountChange(%2 -1) replace restart { jp Z, %2 ld a, #%3 jp %1 %2: xor a, a %1: } by { ld a, #%3 jp NZ, %1 ; peephole 169xz used double assignment in case of Z condition. %2: xor a, a %1: } if labelRefCountChange(%2 -1) replace restart { jp NZ, %2 ld a, #%3 jp %1 %2: xor a, a %1: } by { ld a, #%3 jp Z, %1 ; peephole 169xnz used double assignment in case of NZ condition. %2: xor a, a %1: } if labelRefCountChange(%2 -1) replace restart { jp Z, %2 ld c, #%3 jp %1 %2: ld c, #%4 %1: } by { ld c, #%3 jp NZ, %1 %2: ld c, #%4 ; peephole 170z used double assignment in case of Z condition. %1: } if labelRefCountChange(%2 -1) replace restart { jp NZ, %2 ld c, #%3 jp %1 %2: ld c, #%4 %1: } by { ld c, #%3 jp Z, %1 %2: ld c, #%4 ; peephole 170nz used double assignment in case of NZ condition. %1: } if labelRefCountChange(%2 -1) replace restart { jp Z, %2 ld e, #%3 jp %1 %2: ld e, #%4 %1: } by { ld e, #%3 jp NZ, %1 %2: ld e, #%4 ; peephole 171z used double assignment in case of Z condition. %1: } if labelRefCountChange(%2 -1) replace restart { jp NZ, %2 ld e, #%3 jp %1 %2: ld e, #%4 %1: } by { ld e, #%3 jp Z, %1 %2: ld e, #%4 ; peephole 171nz used double assignment in case of NZ condition. %1: } if labelRefCountChange(%2 -1) replace restart { jp Z, %2 ld l, #%3 jp %1 %2: ld l, #%4 %1: } by { ld l, #%3 jp NZ, %1 %2: ld l, #%4 ; peephole 172z used double assignment in case of Z condition. %1: } if labelRefCountChange(%2 -1) replace restart { jp NZ, %2 ld l, #%3 jp %1 %2: ld l, #%4 %1: } by { ld l, #%3 jp Z, %1 %2: ld l, #%4 ; peephole 172nz used double assignment in case of NZ condition. %1: } if labelRefCountChange(%2 -1) // These ex-generating rules should be among the last ones since ex counts as a read from both hl and de for notUsed(). barrier replace restart { ld d,h ld e,l } by { ; peephole 146 used ex to load hl into de. ex de,hl } if notUsed('hl') replace restart { ld e,l ld d,h } by { ; peephole 147 used ex to load hl into de. ex de,hl } if notUsed('hl') replace restart { ld l,e ld h,d } by { ; peephole 148 used ex to load de into hl. ex de,hl } if notUsed('de') barrier // Should be one of the last ones. Opens the code to further peephole optimization. replace restart { %1: } by { ; peephole 149 removed unused label %1. } if labelRefCount(%1 0) // Ensure that all rules above see only jp, not jr. barrier replace { add hl,de pop de jp (hl) %1: jp %5 jp %6 jp %7 %2: } by { ; peephole 150-3 removed addition using short jumps in jump-table. pop de jp (hl) %1: jr %5 jr %6 jr %7 %2: } if labelJTInRange replace { add hl,de jp (hl) %1: jp %5 jp %6 jp %7 %2: } by { ; peephole 150-3' removed addition using short jumps in jump-table. jp (hl) %1: jr %5 jr %6 jr %7 %2: } if labelJTInRange replace { add hl,de pop de jp (hl) %1: jp %5 jp %6 jp %7 jp %8 %2: } by { ; peephole 150-4 removed addition using short jumps in jump-table. pop de jp (hl) %1: jr %5 jr %6 jr %7 jr %8 %2: } if labelJTInRange replace { add hl,de jp (hl) %1: jp %5 jp %6 jp %7 jp %8 %2: } by { ; peephole 150-4' removed addition using short jumps in jump-table. jp (hl) %1: jr %5 jr %6 jr %7 jr %8 %2: } if labelJTInRange replace { add hl,de pop de jp (hl) %1: jp %5 jp %6 jp %7 jp %8 jp %9 %2: } by { ; peephole 150-5 removed addition using short jumps in jump-table. pop de jp (hl) %1: jr %5 jr %6 jr %7 jr %8 jr %9 %2: } if labelJTInRange replace { add hl,de jp (hl) %1: jp %5 jp %6 jp %7 jp %8 jp %9 %2: } by { ; peephole 150-5' removed addition using short jumps in jump-table. jp (hl) %1: jr %5 jr %6 jr %7 jr %8 jr %9 %2: } if labelJTInRange replace { add hl,de pop de jp (hl) %1: jp %5 jp %6 jp %7 jp %8 jp %9 jp %10 %2: } by { ; peephole 150-6 removed addition using short jumps in jump-table. pop de jp (hl) %1: jr %5 jr %6 jr %7 jr %8 jr %9 jr %10 %2: } if labelJTInRange replace { add hl,de jp (hl) %1: jp %5 jp %6 jp %7 jp %8 jp %9 jp %10 %2: } by { ; peephole 150-6' removed addition using short jumps in jump-table. jp (hl) %1: jr %5 jr %6 jr %7 jr %8 jr %9 jr %10 %2: } if labelJTInRange replace { add hl,de pop de jp (hl) %1: jp %5 jp %6 jp %7 jp %8 jp %9 jp %10 jp %11 %2: } by { ; peephole 150-7 removed addition using short jumps in jump-table. pop de jp (hl) %1: jr %5 jr %6 jr %7 jr %8 jr %9 jr %10 jr %11 %2: } if labelJTInRange replace { add hl,de jp (hl) %1: jp %5 jp %6 jp %7 jp %8 jp %9 jp %10 jp %11 %2: } by { ; peephole 150-7' removed addition using short jumps in jump-table. jp (hl) %1: jr %5 jr %6 jr %7 jr %8 jr %9 jr %10 jr %11 %2: } if labelJTInRange barrier // Do all jump optimizations before replacing by ret. replace restart { jp %5 } by { ret ; peephole 151 replaced jump by return. } if labelIsReturnOnly(%5), labelRefCountChange(%5 -1) replace restart { jp %1,%5 } by { ret %1 ; peephole 152 replaced jump by return. } if labelIsReturnOnly(%5), labelRefCountChange(%5 -1) // Replace jp by ret before replacing jp by jr outside of jump tables, since using ret can reduce the number of references to jump labels. barrier replace { jp %5 } by { jr %5 ; peephole 153 changed absolute to relative unconditional jump. } if labelInRange(%5) replace { jp Z,%5 } by { jr Z,%5 ; peephole 154 changed absolute to relative conditional jump. } if labelInRange(%5) replace { jp NZ,%5 } by { jr NZ,%5 ; peephole 155 changed absolute to relative conditional jump. } if labelInRange(%5) replace { jp C,%5 } by { jr C,%5 ; peephole 156 changed absolute to relative conditional jump. } if labelInRange(%5) replace { jp NC,%5 } by { jr NC,%5 ; peephole 157 changed absolute to relative conditional jump. } if labelInRange(%5) replace { dec b jr NZ, %5 } by { djnz %5 ; peephole 158 used djnz }