+// peeph.def - Common Z80 and gbz80 peephole rules
+//
+// 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 - 2008
+//
+// 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 -1 removed redundant load.
+} if notVolatile(%1)
+
+// This one doesn't work currently since the peephole optimizer can't match lines generated by multiline macros: Bug #1570701
+//replace restart {
+// pop af
+// ld sp,%1
+//} by {
+// ; peephole -1a eleminated dead pop.
+// ld sp,%1
+//} if notUsed('a')
+
+replace restart {
+ ld %1,%2
+} by {
+ ; peephole 0a removed dead load from %2 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,%2
+ ld a,%1
+} by {
+ ; peephole 0b loaded %2 into a directly instead of going through %1.
+ ld a,%2
+} if notVolatile(%1), notUsed(%1)
+
+replace restart {
+ ld %1,%2 (%3)
+ ld a,%1
+} by {
+ ; peephole 0c loaded %2 (%3) into a directly instead of going through %1.
+ ld a,%2 (%3)
+} if notVolatile(%1), notUsed(%1)
+
+replace restart {
+ ld %1,#%2
+ ld a,%3 (%1)
+} by {
+ ; peephole 0d loaded %2 into a directly instead of going through %1.
+ ld a,(#%2+%3)
+} if notUsed(%1)
+
+replace restart {
+ srl %1
+ ld a,%1
+} by {
+ ld a,%1
+ ; peephole 0e shifted in a instead of %1.
+ srl a
+} if notVolatile(%1), notUsed(%1)
+
+replace restart {
+ ld %1,(hl)
+ ld a,%2 (%3)
+ sub a,%1
+} by {
+ ld a,%2 (%3)
+ ; peephole 0f 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 0g incremented in hl instead of bc.
+ inc hl
+} if notUsed('bc')
+
+// Catch double and triple incs before later peepholes introduce an ex de,hl in here.
+replace restart {
+ inc de
+ inc de
+ ld l,e
+ ld h,d
+} by {
+ ld l,e
+ ld h,d
+ ; peephole 0h' incremented in hl instead of de.
+ inc hl
+ inc hl
+} if notUsed('de')
+
+replace restart {
+ inc de
+ ld l,e
+ ld h,d
+} by {
+ ld l,e
+ ld h,d
+ ; peephole 0h incremented in hl instead of de.
+ inc hl
+} if notUsed('de')
+
+replace restart {
+ ld e,%1
+ ld d,%2
+ ld l,e
+ ld h,d
+} by {
+ ; peephole 0i loaded %2%1 into hl directly instead of going through de.
+ ld l,%1
+ ld h,%2
+} if notUsed('de')
+
+replace restart {
+ ld bc,#%2 + %3
+ ld a,(bc)
+ ld c,a
+} by {
+ ; peephole 0j used hl for #%2 + %3 instead of bc, not going through a.
+ ld hl,#%2 + %3
+ ld c,(hl)
+} if notUsed('a'), notUsed('hl')
+
+replace restart {
+ ld de,#%2 + %3
+ ld a,(de)
+ ld e,a
+} by {
+ ; peephole 0j' used hl for #%2 + %3 instead of de, not going through a.
+ ld hl,#%2 + %3
+ ld e,(hl)
+} if notUsed('a'), notUsed('hl')
+
+replace restart {
+ ex de,hl
+ push hl
+} by {
+ ; peephole 0k pushed de directly instead of going through hl.
+ push de
+} if notUsed('de'), notUsed('hl')
+
+replace restart {
+ ex de,hl
+ push de
+} by {
+ ; peephole 0k' 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 0k'' 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 0l 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 0m 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 0m' pushed bc instead of hl removing a load.
+ ld c,%1
+ push bc
+} if notUsed('hl'), notUsed('c')
+
+replace restart {
+ ld c,a
+ push de
+ ld a,c
+} by {
+ ; peephole 0n removed redundant load of a through c.
+ push de
+} if notUsed('c')
+
+replace restart {
+ ld c,e
+ ld b,d
+ ld a,(bc)
+} by {
+ ; peephole 0o used de directly instead of going through bc.
+ ld a,(de)
+} if notUsed('bc')
+
+replace restart {
+ pop de
+ ld l,e
+ ld h,d
+} by {
+ ; peephole 0p popped hl directly instead of going through de.
+ pop hl
+} if notUsed('de')
+
+replace restart {
+ ld %1,a
+ ld %2 (%3),%1
+} by {
+ ; peephole 0q loaded a into %2 (%3) directly instead of going through %1.
+ ld %2 (%3),a
+} if notVolatile(%1), notUsed(%1)
+
+replace restart {
+ ld %1 (ix),%2
+ ld %3, %1 (ix)
+} by {
+ ; peephole 0r loaded %3 from %2 instead of going through %1 (ix).
+ ld %1 (ix),%2
+ ld %3, %2
+}
+// Don't need to check for volatile, since ix is used for the stack.
+
+replace restart {
+ ld %1, %2 (%3)
+ ld b, %1
+} by {
+ ; peephole 0s loaded b from %2 (%3) instead of going through %1.
+ ld b, %2 (%3)
+} if notVolatile(%1), notUsed(%1)
+
+replace restart {
+ ld %1,a
+ ld %2,%3
+ ld %4,%1
+} by {
+ ; peephole 0t loaded %4 from a instead of going through %1.
+ ld %1,a
+ ld %2,%3
+ ld %4,a
+} if notVolatile(%1), operandsNotRelated(%1 %3), operandsNotRelated(%1 %2)
+
+replace restart {
+ ld %1,a
+ ld a,%2
+ adc a,#%3
+ ld %4,%1
+} by {
+ ld %1,a
+ ; peephole 0t' loaded %4 from a instead of going through %1.
+ ld %4,a
+ ld a,%2
+ adc a,#%3
+} if notVolatile(%1), operandsNotRelated(%1 %2), operandsNotRelated(%4 %2)
+
+replace restart {
+ ld %1,a
+ ld a,#%2
+ adc a,#%3
+ ld %4,%1
+} by {
+ ld %1,a
+ ; peephole 0t'' loaded %4 from a instead of going through %1.
+ ld %4,a
+ ld a,#%2
+ adc a,#%3
+} if notVolatile(%1)
+
+replace restart {
+ ld %1,(hl)
+ ld e,%1
+} by {
+ ; peephole 0u loaded e from (hl) instead of going through %1.
+ ld e,(hl)
+} if notUsed(%1)
+
+replace restart {
+ ld %1,l
+ ld %2 (%3),%1
+} by {
+ ; peephole 0v loaded %2 (%3) from l instead of going through %1.
+ ld %2 (%3),l
+} if notUsed(%1)
+
+replace restart {
+ ld l,%1 (ix)
+ ld h,%2 (ix)
+ ld %3,(hl)
+ srl %3
+ ld l,%1 (ix)
+ ld h,%2 (ix)
+ ld (hl),%3
+} by {
+ ld l,%1 (ix)
+ ld h,%2 (ix)
+ ; peephole 0w shifted (hl) in place.
+ srl (hl)
+ ld %3,(hl)
+} if notVolatile(%3)
+// Don't check for volatile since ix points to the stack.
+
+replace restart {
+ push af
+ inc sp
+ ld a,e
+ push af
+ inc sp
+} by {
+ ; peephole 0x 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,c
+ push af
+ inc sp
+} by {
+ ; peephole 0y pushed bc instead of pushing a twice.
+ ld b,a
+ push bc
+} if notUsed('b'), notUsed('a')
+
+replace restart {
+ ld a,#%1
+ ld d,a
+} by {
+ ; peephole 0z loaded #%1 into d directly instead of going through a.
+ ld d,#%1
+} if notUsed('a')
+
+replace restart {
+ ld a,%1 (ix)
+ push af
+ inc sp
+ ld a,%2 (ix)
+ push af
+ inc sp
+} by {
+ ; peephole 0za 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 0zb pushed hl instead of bc.
+ push hl
+} if notUsed('bc')
+
+// Doesn'T work due to bug #1947081
+//replace restart {
+// pop %1
+// push %1
+//} by {
+// ; peephole 0zc eleminated dead pop/push pair.
+//} if notUsed(%1)
+
+replace restart {
+ ld iy,#%1
+ or a,%2 (iy)
+} by {
+ ; peephole 0zd 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 (%4)
+} by {
+ ; peephole 0ze used hl instead of iy.
+ ld hl,#%1 + %3
+ ld %2,(hl)
+} if notUsed('iy'), notUsed('hl')
+
+replace restart {
+ ld iy,#%1
+ ld %2 (%3), %4
+} by {
+ ; peephole 0zf used hl instead of iy.
+ ld hl,#%1 + %2
+ ld (hl), %4
+} if notUsed('iy'), notUsed('hl'), operandsNotRelated(%4 'h'), operandsNotRelated(%4 'l')
+
+replace restart {
+ ld e,l
+ ld d,h
+ ld %1,(de)
+} by {
+ ; peephole 0zg loaded %1 from (hl) directly instead of going through (de).
+ ld %1,(hl)
+} if notUsed('de')
+
+replace restart {
+ ld c,l
+ ld b,h
+ ld %1,(bc)
+} by {
+ ; peephole 0zh loaded %1 from (hl) directly instead of going through (bc).
+ ld %1,(hl)
+} if notUsed('bc')
+
+replace restart {
+ ld c,l
+ ld b,h
+ inc bc
+} by {
+ ; peephole 0zi 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 0zj tested bit of %1 (%2) directly instead of going through a.
+ bit %3,%1 (%2)
+} if notUsed('a')
+
+replace restart {
+ ld bc, #%1 + %2
+ ld l,c
+ ld h,b
+} by {
+ ; peephole 0zk stored constant #%1 + %2 into hl directly instead of going through bc.
+ ld hl, #%1 + %2
+} if notUsed('bc')
+
+replace restart {
+ ld c, %1 (%2)
+ ld b, %3 (%4)
+ ld l,c
+ ld h,b
+} by {
+ ; peephole 0zk' 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 {
+ jp NC,%1
+ jp %2
+%1:
+} by {
+ jp C,%2
+ ; peephole 3 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 4 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 5 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 6 removed jp by using inverse jump logic
+%1:
+} if labelRefCountChange(%1 -1)
+
+replace restart {
+ jp %5
+} by {
+ jp %6
+ ; peephole 7 redirected jump-to-jump at %5 by jump to %6
+} if labelIsUncondJump(), labelRefCountChange(%5 -1), labelRefCountChange(%6 +1)
+
+replace restart {
+ jp %1,%5
+} by {
+ jp %1,%6
+ ; peephole 8 redirected jump-to-jump at %5 by jump to %6
+} if labelIsUncondJump(), labelRefCountChange(%5 -1), labelRefCountChange(%6 +1)
+
+replace restart {
+ xor a,a
+ ld a,#0x00
+} by {
+ xor a,a
+ ; peephole 10 removed redundant load of 0 into a.
+}
+
+replace {
+ ld e,#0x%1
+ ld d,#0x%2
+} by {
+ ld de,#0x%2%1
+ ; peephole 11 combined constant loads into register pair.
+}
+
+replace {
+ ld l,#0x%1
+ ld h,#0x%2
+} by {
+ ld hl,#0x%2%1
+ ; peephole 12 combined constant loads into register pair.
+}
+
+replace {
+ ld c,#0x%1
+ ld b,#0x%2
+} by {
+ ld bc,#0x%2%1
+ ; peephole 13 combined constant loads into register pair.
+}
+
+replace restart {
+ ld %1,a
+ ld a,%1
+} by {
+ ld %1,a
+ ; peephole 14 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 15 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 %1,a
+ ld a,%2
+ or a,%1
+} by {
+ ld %1,a
+ or a,%2
+ ; peephole 17a removed load by reordering or arguments.
+} if notVolatile(%1)
+
+replace restart {
+ ld %1,a
+ ld a,%2 (ix)
+ or a,%1
+} by {
+ ld %1,a
+ or a,%2 (ix)
+ ; peephole 17b removed load by reordering or arguments.
+} if notVolatile(%1)
+
+replace restart {
+ ld %1,a
+ xor a,a
+ or a,%1
+} by {
+ ld %1,a
+ or a,a
+ ; peephole 18 used value still in a instead of loading it from %1.
+}
+
+replace restart {
+ or a,%1
+ or a,a
+} by {
+ or a,%1
+ ; peephole 19 removed redundant or after or.
+}
+
+replace restart {
+ or a,%1 (%2)
+ or a,a
+} by {
+ or a,%1 (%2)
+ ; peephole 19a removed redundant or after or.
+}
+
+replace restart {
+ and a,%1
+ or a,a
+} by {
+ and a,%1
+ ; peephole 20 removed redundant or after and.
+}
+
+replace restart {
+ and a,%1 (%2)
+ or a,a
+} by {
+ and a,%1 (%2)
+ ; peephole 20a removed redundant or after and.
+}
+
+replace restart {
+ xor a,%1
+ or a,a
+} by {
+ xor a,%1
+ ; peephole 21 removed redundant or after xor.
+}
+
+replace restart {
+ xor a,%1 (%2)
+ or a,a
+} by {
+ xor a,%1 (%2)
+ ; peephole 21a removed redundant or after xor.
+}
+
+replace {
+ ld %1,%2
+ ld a,%2
+} by {
+ ld a,%2
+ ld %1,a
+ ; peephole 23 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 24 removed redundant load from %3%1 into %4%2
+} if notVolatile(%1 %2 %3 %4)
+
+replace restart {
+ ld a,c
+ push af
+ inc sp
+ ld a,#%2
+ push af
+ inc sp
+ call %3
+} by {
+ ld b,c
+ ld c,#%2
+ push bc
+ ; peephole 31 moved and pushed arguments c and #%2 through bc instead of pushing them individually.
+ call %3
+}
+
+replace restart {
+ ld a,e
+ push af
+ inc sp
+ ld a,#%2
+ push af
+ inc sp
+ call %3
+} by {
+ ld d,e
+ ld e,#%2
+ push de
+ ; peephole 32 moved and pushed arguments e and #%2 through de instead of pushing them individually.
+ call %3
+}
+
+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 33 removed load by replacing sub with cp
+ assert a=%1
+} if notVolatile(%1)
+
+replace restart {
+ assert a=%1
+ sub a,%2
+ jp %3,%4
+ ld a,%1
+} by {
+ cp a,#%2
+ jp %3,%4
+ ; peephole 34 removed load by replacing sub with cp
+ assert a=%1
+}
+
+replace restart {
+ assert a=%1
+} by {
+}
+
+replace restart {
+ sub a,#0xFF
+ jp Z,%1
+} by {
+ inc a
+ ; peephole 35 replaced sub a,#0xFF by inc a.
+ jp Z,%1
+}
+
+replace restart {
+ sub a,#0xFF
+ jp NZ,%1
+} by {
+ inc a
+ ; peephole 36 replaced sub a,#0xFF by inc a.
+ jp NZ,%1
+}
+
+replace restart {
+ ld bc,#%1 + %2
+ ld a,c
+ add a,%3
+ ld c,a
+ ld a,b
+ adc a,%4
+ ld b,a
+} by {
+ ld a,#<(%1 + %2)
+ add a,%3
+ ld c,a
+ ld a,#>(%1 + %2)
+ ; peephole 37 directly used (%1 + %2) in calculation instead of placing it in bc first.
+ adc a,%4
+ ld b,a
+}
+
+replace restart {
+ ld de,#%1 + %2
+ ld a,e
+ add a,%3
+ ld e,a
+ ld a,d
+ adc a,%4
+ ld d,a
+} by {
+ ld a,#<(%1 + %2)
+ add a,%3
+ ld e,a
+ ld a,#>(%1 + %2)
+ ; peephole 38 directly used (%1 + %2) in calculation instead of placing it in de first.
+ adc a,%4
+ ld d,a
+}
+
+replace restart {
+ rlca
+ ld a,#0x00
+ rla
+} by {
+ rlca
+ and a,#0x01
+ ; peephole 39 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 40 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 41 removed lower part of multibyte addition.
+ ld %2,a
+ ld a,%3
+ add a,%4
+}
+
+replace restart {
+ ld %1,a
+ ld a,%2
+ add a,%1
+} by {
+ ; peephole 42 removed loads by exploiting commutativity of addition.
+ add a,%2
+} if notVolatile(%1), notUsed(%1), operandsNotRelated(%2 '(bc)' '(de)')
+
+replace restart {
+ ld %1 (ix),a
+ ld a,#%2
+ add a,%1 (ix)
+} by {
+ ld %1 (ix),a
+ ; peephole 42a 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.
+
+// sdcc does not use the H flag. sla resets it, while add sets it.
+// To ensure that the state of the H flag is not changed by this
+// peephole uncomment the add %3, %4 at the end (since it overwrite the H flag).
+replace restart {
+ ld %1, a
+ sla %1
+ ld a, %2
+ //add %3, %4
+} by {
+ add a, a
+ ; peephole 42b shifted in accumulator insted of %1
+ ld %1, a
+ ld a, %2
+ //add %3, %4
+}
+
+// sdcc does not use the H flag. sla resets it, while add sets it.
+// To ensure that the state of the H flag is not changed by this
+// peephole uncomment the add %3, %4 at the end (since it overwrite the H flag).
+replace restart {
+ ld %1, a
+ sla %1
+ sla %1
+ ld a, %2
+ //add %3, %4
+} by {
+ add a, a
+ add a, a
+ ; peephole 42b' shifted in accumulator insted of %1
+ ld %1, a
+ ld a, %2
+ //add %3, %4
+}
+
+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 42c incremented in (hl) instead of going through a.
+} if notUsed('a')
+
+replace restart {
+ ld l,%1 (ix)
+ ld h,%2 (ix)
+ ld a,(hl)
+ dec a
+ ld l,%1 (ix)
+ ld h,%2 (ix)
+ ld (hl),a
+} by {
+ ld l,%1 (ix)
+ ld h,%2 (ix)
+ dec (hl)
+ ; peephole 42d decremented in (hl) instead of going through a.
+} if notUsed('a')
+
+replace restart {
+ ld %1,a
+ ld a,%2
+ add a,%1
+} by {
+ ld %1, a
+ ; peephole 43 removed load by exploiting commutativity of addition.
+ add a,%2
+} if operandsNotRelated(%2 '(bc)' '(de)')
+
+replace restart {
+ ld c,l
+ ld b,h
+ ld hl,#%1
+ add hl,bc
+} by {
+ ; peephole 43a 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 43b 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 43c removed loads by exploiting commutativity of addition.
+ ld hl,#%1
+ add hl,de
+} if notUsed('bc')
+
+replace restart {
+ or a,%1
+ jp NZ,%2
+ xor a,a
+ or a,%3
+} by {
+ or a,%1
+ jp NZ,%2
+ ; peephole 44 removed redundant zeroing of a (which has just been tested to be #0x00).
+ or a,%3
+}
+
+replace restart {
+ or a,%1
+ jp NZ,%2
+ ld %3,#0x00
+} by {
+ or a,%1
+ jp NZ,%2
+ ld %3,a
+ ; peephole 45 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 46 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 47 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 48 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 49 shortened or using a (which has just been tested to be #0x00).
+//} if operandsNotSame3(%3 '(bc)' '(de)')
+
+//replace restart {
+// and a,%1
+// jp NZ,%2
+// ld a,%3
+// or a,a
+//} by {
+// and a,%1
+// jp NZ,%2
+// or a,%3
+// ; peephole 50 shortened or using a (which has just been tested to be #0x00).
+//} if operandsNotSame3(%3 '(bc)' '(de)')
+
+// Commented out sine it triggers for %3 od the form (#...)
+//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 51 shortened or using a (which has just been tested to be #0x00).
+//}
+//if operandsNotSame3(%3 '(bc)' '(de)')
+
+replace restart {
+ dec a
+ jp NZ,%1
+ ld a,%2
+ or a,a
+} by {
+ dec a
+ jp NZ,%1
+ or a,%2
+ ; peephole 52 shortened or using a (which has just been tested to be #0x00).
+}
+//if operandsNotSame3(%2 '(bc)' '(de)')
+
+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 53 replaced constant #0x00 by a (which has just been tested to be #0x00).
+}
+
+replace restart {
+ and a,%1
+ jp NZ,%2
+ push %3
+ ld %4,#0x00
+} by {
+ sub a,%1
+ jp NZ,%2
+ push %3
+ ld %4,a
+ ; peephole 54 replaced constant #0x00 by a (which has just been tested to be #0x00).
+}
+
+replace restart {
+ sub a,%1
+ jp NZ,%2
+ push %3
+ ld %4,#0x00
+} by {
+ sub a,%1
+ jp NZ,%2
+ push %3
+ ld %4,a
+ ; peephole 55 replaced constant #0x00 by a (which has just been tested to be #0x00).
+}
+
+replace restart {
+ dec a
+ jp NZ,%1
+ push %2
+ ld %3,#0x00
+} by {
+ dec a
+ jp NZ,%1
+ push %2
+ ld %3,a
+ ; peephole 56 replaced constant #0x00 by a (which has just been tested to be #0x00).
+}
+
+replace restart {
+ ld de,#%1 + %2
+ inc de
+} by {
+ ld de,#%1 + %2+1
+ ; peephole 59 moved increment of de to constant.
+}
+
+replace restart {
+ ld bc,#%1 + %2
+ inc bc
+} by {
+ ld bc,#%1 + %2+1
+ ; peephole 62 moved increment of bc to constant.
+}
+
+replace restart {
+ ld bc,#%1
+ ld a,c
+ add a,#0x%2
+ ld c,a
+ ld a,b
+ adc a,#0x%3
+ ld b,a
+} by {
+ ld bc,#%1 + 0x%3%2
+ ; peephole 63 moved addition of constant 0x%3%2 to bc to constant.
+}
+
+replace restart {
+ call %1
+ ret
+} by {
+ jp %1
+ ; peephole 65 replaced call at end of function by jump.
+}
+
+// Callee saves ix.
+replace restart {
+ call %1
+ pop ix
+ ret
+} by {
+ pop ix
+ jp %1
+ ; peephole 66 replaced call at end of function by jump moving call beyond pop ix.
+}
+
+replace restart {
+ ld %1,a
+ ld %2,%1
+ ld %3,%1
+} by {
+ ; peephole 67 loaded %2, %3 from a instead of %1.
+ ld %1,a
+ ld %2,a
+ ld %3,a
+} if notVolatile(%1)
+
+replace restart {
+ ld %1,a
+ ld %2,a
+ ld %3,%1
+} by {
+ ld %1,a
+ ld %2,a
+ ; peephole 68 loaded %3 from a instead of %1.
+ ld %3,a
+} if notVolatile(%1)
+
+replace restart {
+ ld %1,l
+ xor a,a
+ or a,%1
+} by {
+ ld %1,l
+ xor a,a
+ ; peephole 69 used l in or instead of %1.
+ or a,l
+} if notVolatile(%1)
+
+replace restart {
+ ld %1,#%2
+ ld %3,%4
+ ld %1,#%2
+} by {
+ ld %1,#%2
+ ld %3,%4
+ ; peephole 70 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 70a used #%1 from hl for load into de.
+ ld hl,#%1
+ ld e,l
+ ld d,h
+}
+
+replace restart {
+ ld hl,#%1
+ push hl
+ ld l,e
+ ld h,d
+ jp (hl)
+%1:
+} by {
+ ; peephole 71 used ex to get de into hl.
+ ex de,hl
+ ld de,#%1
+ push de
+ jp (hl)
+%1:
+}
+// Lets' hope this is never applied to a jump table. It's fine for calls.
+
+// Should be after 0z.
+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 72 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 l, %1
+} by {
+ ld l, a
+ ld a, %2 (%3)
+ adc a, #%4
+ ; peephole 76 loaded l from a directly instead of going through %1.
+} if notUsed(%1)
+
+replace restart {
+ ld %1, a
+ ld a, #%2
+ adc a, #%3
+ ld l, %1
+} by {
+ ld l, a
+ ld a, #%2
+ adc a, #%3
+ ; peephole 77 loaded l from a directly instead of going through %1.
+} if notUsed(%1)
+
+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 78 removed addition and loads exploiting commutativity of addition.
+} if notUsed('de')
+
+replace restart {
+ ex de, hl
+ ld hl, #%1
+ add hl, de
+} by {
+ ; peephole 78a removed ex exploiting commutativity of addition.
+ ld de, #%1
+ add hl, de
+} if notUsed('de')
+
+replace restart {
+ ld hl, #%1
+ add hl, %2
+ ex de, hl
+ inc de
+} by {
+ ld hl, #%1+1
+ ; peephole 79 moved increment to constant.
+ add hl, %2
+ ex de, hl
+} if notUsed('hl')
+
+// These ex-generating rules should be among the last ones since ex counts as a read from both hl and de for notUsed().
+replace restart {
+ ld d,h
+ ld e,l
+} by {
+ ; peephole 80 used ex to load hl into de.
+ ex de,hl
+} if notUsed('hl')
+
+replace restart {
+ ld e,l
+ ld d,h
+} by {
+ ; peephole 81 used ex to load hl into de.
+ ex de,hl
+} if notUsed('hl')
+
+replace restart {
+ ld l,e
+ ld h,d
+} by {
+ ; peephole 82 used ex to load de into hl.
+ ex de,hl
+} if notUsed('de')
+
// peeph-z80.def - Z80 peephole rules
//
//
replace restart {
ld %1,#%2
- ld a,0(%1)
- ld %3,a
+ ld a,%3 (%1)
+ ld %4,a
ld %1,#%5
} by {
- ld a,(#%2)
+ ld a,(#%2 + %3)
; peephole z1 used #%2 directly instead of going through %1 using indirect addressing.
- ld %3,a
+ ld %4,a
ld %1,#%5
}
replace restart {
ld %1,#%2
- ld 0(%1),a
+ ld %3 (%1),a
%4:
ld %1,%5
} by {
- ld (#%2),a
+ ld (#%2 + %3),a
; peephole z2 directly used #%2 instead of going through %1 using indirect addressing.
%4:
ld %1,%5
replace restart {
pop af
ld %1,#%2
- ld 0(%1),%3
- ld %1,#%4
+ ld %3 (%1),%4
+ ld %1,#%5
} by {
- ld a,%3
- ld (#%2),a
+ ld a,%4
+ ld (#%2 + %3),a
; peephole z3 used #%2 directly instead of going through %1 using indirect addressing.
pop af
- ld %1,#%4
+ ld %1,#%5
} if operandsNotRelated(%3 'a')
replace restart {
ld bc,#%1 + %2
ld a,%3
ld (bc),a
- ld bc,#%4 + %5
} by {
ld a,%3
ld (#%1 + %2),a
; peephole z4 directly used address #%1 + %2 instead of placing it in bc first.
- ld bc,#%4 + %5
-}
+} if notUsed('bc')
replace restart {
ld bc,#%1 + %2 + %6
ld a,%3
ld (bc),a
- ld bc,#%4 + %5
} by {
ld a,%3
ld (#%1 + %2 + %6),a
; peephole z5 directly used address #%1 + %2 + %6 instead of placing it in bc first.
- ld bc,#%4 + %5
-}
-
-replace restart {
- ld bc,#%1 + %2
- ld a,%3
- ld (bc),a
-%7:
- ld bc,#%4 + %5
-} by {
- ld a,%3
- ld (#%1 + %2),a
- ; peephole z6 directly used address #%1 + %2 instead of placing it in bc first.
-%7:
- ld bc,#%4 + %5
-}
-
-replace restart {
- ld bc,#%1 + %2 + %6
- ld a,%3
- ld (bc),a
-%7:
- ld bc,#%4 + %5
-} by {
- ld a,%3
- ld (#%1 + %2 + %6),a
- ; peephole z7 directly used address #%1 + %2 + %6 instead of placing it in bc first.
-%7:
- ld bc,#%4 + %5
-}
+} if notUsed('bc')
replace restart {
ld c,%1
jp %1,%5
} by {
ret %1
- ; peephole z12 replaced jump by return.
+ ; peephole z11a replaced jump by return.
} if labelIsReturnOnly(), labelRefCountChange(%5 -1)
// Should be one of the last ones. Opens the code to further peephole optimization.
replace restart {
%1:
} by {
- ; peephole z13 removed unused label %1.
+ ; peephole z12 removed unused label %1.
} if labelRefCount(%1 0)
+// Applying z11 or z11a followed by z12 will often leave a dead ret at the end of the function. Remove it.
+replace {
+ jp %5
+ ret
+} by {
+ jp %5
+ ; peephole z13 removed unused ret.
+}
+
+// These four need two be here since the peephole optimizer continues to apply rules further down the file even for replace restart rules.
+replace restart {
+ jp NC,%1
+ jp %2
+%1:
+} by {
+ jp C,%2
+ ; peephole 5' 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 5' 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 5' 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 6' removed jp by using inverse jump logic
+%1:
+} if labelRefCountChange(%1 -1)
+
// These should be the last rules, so that the peepholes above need to look at jp only.
replace {
jp %5
} by {
jr %5
- ; peephole z14 changed absolute to relative conditional jump.
+ ; peephole z14 changed absolute to relative unconditional jump.
} if labelInRange()
replace {