// peeph-z80.def - 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
//
// 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 {
	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, %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(%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	%3 (ix), %1
	ld	%4 (ix), %2
	ld	%5, %3 (ix)
	ld	%6, %4 (ix)
} by {
	ld	%3 (ix), %1
	ld	%4 (ix), %2
	; peephole 11 loaded %5%6 from %1%2 directly instead of going through %3 (ix) %4 (ix).
	ld	%5, %1
	ld	%6, %2
} if canAssign(%5 %1), canAssign(%6 %2), notSame(%5 %2)

replace restart {
	ld	%1, %2 (%3)
	ld	%4, %1
} by {
	; peephole 12 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 13 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 14 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, %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 {
	ld	a, %1 (%2)
	srl	a
	ld	%1 (%2), a
} by {
	srl	%1 (%2)
	ld	a, %1 (%2)
	; peephole 21 shifted in (%2) instead of a.
}

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	c,l
	ld	b,h
	push	%1
	push	bc
} by {
	; peephole 30 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 31 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 32 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 33 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 34 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	de
	inc	sp
	push	af
	inc	sp
} by {
	; peephole 36 pushed de instead of pushing twice.
	ld	e, a
	push	de
} if notUsed('e'), notUsed('a')

replace restart {
	push	af
	inc	sp
	ld	a,#%1
	push	af
	inc	sp
} by {
	; peephole 37 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 38 pushed bc instead of pushing a twice.
	ld	b,a
	ld	c,#%1
	push	bc
} if notUsed('bc')

replace restart {
	push	hl
	inc	sp
	push	de
	inc	sp
} by {
	ld	l, d
	; peephole 39 combined pushing of b and d.
	push	hl
} if notUsed('l')

replace restart {
	push	bc
	inc	sp
	push	de
	inc	sp
} by {
	ld	c, d
	; peephole 40 combined pushing of b and d.
	push	bc
} if notUsed('c')

replace restart {
	push	de
	inc	sp
	push	bc
	inc	sp
} by {
	ld	e, b
	; peephole 41 combined pushing of d and b.
	push	de
} if notUsed('e')

replace restart {
	push	af
	inc	sp
	ld	a, c
	push	af
	inc	sp
} by {
	ld	b, a
	; peephole 42 combined pushing of a and c.
	push	bc
} if notUsed('b'), notUsed('a')

replace restart {
	push	de
	inc	sp
	ld	a, c
	push	af
	inc	sp
} by {
	ld	e, c
	; peephole 43 combined pushing of d and c.
	push	de
} if notUsed('e'), notUsed('a')

replace restart {
	ld	a, e
	push	af
	inc	sp
	ld	a, %2 (ix)
	push	af
	inc	sp
} by {
	ld	d, e
	ld	e, %2 (ix)
	; peephole 44 combined pushing of e and %2 (ix).
	push	de
} if notUsed('d'), notUsed('e'), notUsed('a')

replace restart {
	ld	a,#%1
	ld	d,a
} by {
	; peephole 45 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 46 loaded %2 from a directly instead of going through %1.
	ld	%2,a
} if notUsed(%1)

replace restart {
	ld	a, %1 (%3)
	push	af
	inc	sp
	ld	a, %2 (%3)
	push	af
	inc	sp
} by {
	; peephole 47 pushed %1 (%3), %2 (%3) through hl instead of af.
	ld	h, %1 (%3)
	ld	l, %2 (%3)
	push	hl
} if notUsed('a'), notUsed('hl')

replace restart {
	ld	c, l
	ld	b, h
	push	bc
} by {
	; peephole 48 pushed hl instead of bc.
	push	hl
} if notUsed('bc')

replace restart {
	ld	a, (hl)
	inc	hl
	ld	h, (hl)
	ld	l, a
	push	hl
} by {
	; peephole 49 pushed bc instead of hl.
	ld	c, (hl)
	inc	hl
	ld	b, (hl)
	push	bc
} if notUsed('bc'), notUsed('hl')

replace restart {
	pop	%1
	push	%1
} by {
	; peephole 50 eleminated dead pop/push pair.
} if notUsed(%1)

replace restart {
	pop	%1
	ld	%2 (ix), %3
	push	%1
} by {
	; peephole 51 eleminated dead pop/push pair.
	ld	%2 (ix), %3
} if notUsed(%1), operandsNotRelated(%1 %3)

replace restart {
	push	hl
	pop	bc
} by {
	ld	c, l
	ld	b, h
	; peephole 52 replaced push/pop pair by loads.
} if notUsed('hl')

replace restart {
	push	hl
	pop	de
} by {
	ld	e, l
	ld	d, h
	; peephole 53 replaced push/pop pair by loads.
} if notUsed('hl')

replace restart {
	ld	iy,#%1
	or	a,%2 (iy)
} by {
	; peephole 54 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 55 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 56 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 57 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 58 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 59 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 60 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 61 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 62 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 63 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 64 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 65 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
	add	iy, sp
	ld	a, 1 (iy)
	or	a, 0 (iy)
} by {
	ld	hl, #%1+1
	add	hl, sp
	ld	a, (hl)
	dec	hl
	or	a, (hl)
	; peephole 66 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 67 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 68 used hl instead of iy.
} if notUsed('iy'), notUsed('hl')

replace restart {
	ld	c,l
	ld	b,h
	inc	bc
} by {
	; peephole 69 incremented in hl instead of bc.
	inc	hl
	ld	c,l
	ld	b,h
} if notUsed('hl')

replace restart {
	ld	iy, #%1
	inc	%2 (iy)
} by {
	; peephole 70 incremented in (hl) instead of %2 (iy).
	ld	hl, #%1+%2
	inc	(hl)
} if notUsed('hl'), notUsed('iy')

replace restart {
	ld	iy, #%1
	dec	%2 (iy)
} by {
	; peephole 71 decremented in (hl) instead of %2 (iy).
	ld	hl, #%1+%2
	dec	(hl)
} if notUsed('hl'), notUsed('iy')

replace restart {
	ld	a,%1 (%2)
	bit	%3,a
} by {
	; peephole 72 tested bit %3 of %1 (%2) directly instead of going through a.
	bit	%3,%1 (%2)
} if notUsed('a')

replace restart {
	ld	%1, (hl)
	bit	%2, %1
} by {
	; peephole 73 tested bit %2 of (hl) directly instead of going through %1.
	bit	%2, (hl)
} if notUsed(%1)

replace restart {
	ld	a,%1
	bit	%2,a
} by {
	; peephole 74 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 75 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 76 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 77 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 78 reset bit %3 of %1 (%2) directly instead of going through a.
	res	%3, %1 (%2)
	ld	a, %1 (%2)
}

replace restart {
	jp	NC,%1
	jp	%2
%1:
} by {
	jp	C,%2
	; peephole 79 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 80 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 81 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 82 removed jp by using inverse jump logic
%1:
} if labelRefCountChange(%1 -1)

replace restart {
	jp	%5
} by {
	jp	%6
	; peephole 83 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 84 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 85 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 86 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 87 removed unreachable jump to %3.
}

replace restart {
	ld	%1, %2
	jp	%3
%3:
} by {
	ld	%1, %2
%3:
	; peephole 88 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 89 removed impossible jump to %2.
} if labelRefCountChange(%2 -1)
	
replace restart {
	rlca
	and	a, #0x01
	jp	Z, %1
} by {
	rlca
	; peephole 90 removed and by changing jump condition.
	jp	NC, %1
} if notUsed('a'), notUsedFrom(%1 'a')

replace restart {
	rlca
	and	a, #0x01
	jp	NZ, %1
} by {
	rlca
	; peephole 91 removed and by changing jump condition.
	jp	C, %1
} if notUsed('a'), notUsedFrom(%1 'a')

replace {
	ld	e, #0x%1
	ld	d, #0x%2
} by {
	ld	de, #0x%2%1
	; peephole 92 combined constant loads into register pair.
}

replace {
	ld	d, #0x%1
	ld	e, #0x%2
} by {
	ld	de, #0x%1%2
	; peephole 93 combined constant loads into register pair.
}

replace {
	ld	l, #0x%1
	ld	h, #0x%2
} by {
	ld	hl, #0x%2%1
	; peephole 94 combined constant loads into register pair.
}

replace {
	ld	h, #0x%1
	ld	l, #0x%2
} by {
	ld	hl, #0x%1%2
	; peephole 95 combined constant loads into register pair.
}

replace {
	ld	c, #0x%1
	ld	b, #0x%2
} by {
	ld	bc, #0x%2%1
	; peephole 96 combined constant loads into register pair.
}

replace {
	ld	b, #0x%1
	ld	c, #0x%2
} by {
	ld	bc, #0x%1%2
	; peephole 97 combined constant loads into register pair.
}

replace restart {
	ld	%1,a
	ld	a,%1
} by {
	ld	%1,a
	; peephole 98 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	%1,a
	ld	a,%2
	or	a,%1
} by {
	ld	%1,a
	or	a,%2
	; peephole 99 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 {
	ld	%1, (hl)
	inc	hl
	ld	a, (hl)
	or	a, %1
} by {
	ld	a, (hl)
	inc	hl
	; peephole 99a removed load by reordering or arguments.
	or	a, (hl)
} if notUsed(%1)

replace restart {
	and	a,%1
	or	a,a
} by {
	and	a,%1
	; peephole 100 removed redundant or after and.
}

replace restart {
	xor	a,%1
	or	a,a
} by {
	xor	a,%1
	; peephole 101 removed redundant or after xor.
}

replace restart {
	xor	a,%1 (%2)
	or	a,a
} by {
	xor	a,%1 (%2)
	; peephole 102 removed redundant or after xor.
}

replace {
	ld	%1,%2
	ld	a,%2
} by {
	ld	a,%2
	ld	%1,a
	; peephole 103 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 104 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 105 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 106 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 107 removed load from %1 into a 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 108 removed load from %1 into a by replacing sub with cp
	assert	a=%1
} if notUsedFrom(%4 'a')

replace restart {
	assert	a=%1
} by {
}

replace restart {
	rlca
	ld	a,#0x00
	rla
} by {
	rlca
	and	a,#0x01
	; peephole 109 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 110 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 111 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 112 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 113 used 16-bit addition.
	ld	c, l
	ld	b, h
	ld	a, h
} if notUsed('hl')

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 114 incremented in (hl) instead of going through a.
} if notUsed('a')

replace restart {
	ld	a,(hl)
	inc	a
	ld	(hl),a
} by {
	inc	(hl)
	; peephole 115 incremented in (hl) instead of going through a.
} if notUsed('a')

// TODO: Check for volatile?
replace restart {
	ld	%1, %2 (%3)
	inc	%1
	ld	%2 (%3), %1
} by {
	inc	%2 (%3)
	ld	%1, %2 (%3)
	; peephole 116 incremented in %2 (%3) instead of going through %1.
}

// TODO: Check for volatile?
replace restart {
	ld	%1, %2 (%3)
	dec	%1
	ld	%2 (%3), %1
} by {
	dec	%2 (%3)
	ld	%1, %2 (%3)
	; peephole 117 decremented in %2 (%3) instead of going through %1.
}

replace restart {
	ld	%1,a
	ld	a,%2
	add	a,%1
} by {
	ld	%1, a
	; peephole 118 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 119 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 120 removed loads by exploiting commutativity of addition.
	ld	hl,#%1 + %4
	add	hl,%2
} 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 121 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 122 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 123 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 124 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 125 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 126 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 127 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 {
	ld	(hl),#0x00
	inc	hl
	ld	(hl),#0x00
	inc	hl
	ld	(hl),#0x00
} by {
	xor	a, a
	; peephole 128a cached zero in a.
	ld	(hl), a
	inc	hl
	ld	(hl), a
	inc	hl
	ld	(hl), a
} if notUsed('a')

replace restart {
	ld	(hl),#0x00
	inc	hl
	ld	(hl),#0x00
} by {
	xor	a, a
	; peephole 128b cached zero in a.
	ld	(hl), a
	inc	hl
	ld	(hl), a
} if notUsed('a')

replace restart {
	ld	hl,#%1
	add	hl,%2
	inc	hl
} by {
	ld	hl,#%1+1
	add	hl,%2
	; peephole 129 moved increment of hl to constant.
}

replace restart {
	push	hl
	pop	iy
	pop	hl
	inc	iy
} by {
	inc	hl
	push	hl
	pop	iy
	pop	hl
	; peephole 130 incremented in hl instead of iy.
}

replace restart {
	push	bc
	pop	iy
	inc	iy
} by {
	inc	bc
	push	bc
	pop	iy
	; peephole 131 incremented in bc instead of iy.
} if notUsed('bc')

replace restart {
	ld	hl,%1
	add	hl,%2
	push	hl
	pop	iy
} by {
	ld	iy,%1
	add	iy,%2
	; peephole 132 added in iy instead of hl.
} if notUsed('hl'), notSame(%2 'hl')

replace restart {
	pop	af
	ld	sp,%1
} by {
	; peephole 133 removed redundant pop af.
	ld	sp,%1
} if notUsed('a')

replace restart {
	inc	sp
	ld	sp,%1
} by {
	; peephole 134 removed redundant inc sp.
	ld	sp,%1
} if notUsed('a')

replace restart {
	call    %1
	ret
} by {
	jp  %1
	; peephole 135 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
	; peephole 136 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 137 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 138 used #%1 from hl for load into de.
	ld	hl,#%1
	ld	e,l
	ld	d,h
}

replace restart {	
	ld      sp,hl
	ld      hl,#0x0002
	add     hl,sp
} by {
	ld	sp, hl
	inc	hl
	inc	hl
	; peephole 139 replaced addition by increment.
}

replace restart {
	ex	de, hl
	ld	hl, #%1
	add	hl, de
} by {
	; peephole 140 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 141 moved increment to constant.
	add	hl, %2
	ex	de, hl
} if notUsed('hl')

replace restart {
	pop	af
	push	hl
} by {
	; peephole 142 used ex to move hl onto the stack.
	ex	(sp),hl
} if notUsed('a'), notUsed('hl')

replace restart {
	pop	af
	ld	hl, #%1
	push	hl
} by {
	ld	hl, #%1
	; peephole 143 used ex to move hl onto the stack.
	ex	(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 144 used ex to move #%1 onto the stack.
	ex	(sp),hl
} if notUsed('a'), notUsed('hl')

replace restart {
	pop	af
	inc	sp
	ld	h, %1 (ix)
	ld	l, %2 (ix)
	push	hl
} by {
	inc	sp
	ld	h, %1 (ix)
	ld	l, %2 (ix)
	; peephole 145 used ex to move %1 (ix) %2 (ix) onto the stack.
	ex	(sp),hl
} if notUsed('a'), notUsed('hl')

replace restart {
	pop	af
	ld	a,#%1
	push	af
	inc	sp
} by {
	ld	h,#%1
	ex	(sp),hl
	; peephole 146 used ex 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 147 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 148 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 149 tested bit %2 of a directly instead of going through %1.
} if notUsed(%1)

replace restart {
	sbc	a,%1
	bit	7,a
	jp	NZ,%2
} by {
	sbc	a,%1
	jp	M,%2
	; peephole 150 used sign flag instead of testing bit 7.
}

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 151 used value still in a instead of reloading from %1.
}

replace {
	jp	%5
	ret
} by {
	jp	%5
	; peephole 152 removed unused ret.
}

replace {
	jp	%5
	ld	sp,ix
	pop	ix
	ret
} by {
	jp	%5
	; peephole 153 removed unused ret.
}

replace restart {
	or	a,%1
	jp	NZ,%2
	xor	a,a
	jp	%3
} by {
	or	a,%1
	jp	NZ,%2
	; peephole 155 removed redundant zeroing of a (which has just been tested to be #0x00).
	jp	%3
}

// 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	e,l
	ld	d,h
} by {
	; peephole 156 used ex to load hl into de.
	ex	de,hl
} if notUsed('hl')

replace restart {
	ld	l,e
	ld	h,d
} by {
	; peephole 157 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 158 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 159-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 159-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 159-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 159-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 159-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 159-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 159-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 159-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 159-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 159-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 160 replaced jump by return.
} if labelIsReturnOnly(%5), labelRefCountChange(%5 -1)

replace restart {
	jp	%1,%5
} by {
	ret	%1
	; peephole 161 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 162 changed absolute to relative unconditional jump.
} if labelInRange(%5)

replace {
	jp	Z,%5
} by {
	jr	Z,%5
	; peephole 163 changed absolute to relative conditional jump.
} if labelInRange(%5)

replace {
	jp	NZ,%5
} by {
	jr	NZ,%5
	; peephole 164 changed absolute to relative conditional jump.
} if labelInRange(%5)

replace {
	jp	C,%5
} by {
	jr	C,%5
	; peephole 165 changed absolute to relative conditional jump.
} if labelInRange(%5)

replace {
	jp	NC,%5
} by {
	jr	NC,%5
	; peephole 166 changed absolute to relative conditional jump.
} if labelInRange(%5)

replace {
	dec b
	jr	NZ,	%5	
} by {
	djnz	%5
	; peephole 167 used djnz
}

barrier

// To weird to let any other peephole rules see the result of the rules below

replace {
	jr	Z, %2
	ld	a, #%3
	jr	%1
%2:
	ld	a, #%4
%1:
} by {
	jr	Z, %2
	ld	a, #%3
	.db	#0xca
	; peephole 168z used jp Z opcode to jump over 2-byte instruction.
%2:
	ld	a, #%4
%1:
}

replace {
	jr	NZ, %2
	ld	a, #%3
	jr	%1
%2:
	ld	a, #%4
%1:
} by {
	jr	NZ, %2
	ld	a, #%3
	.db	#0xc2
	; peephole 168nz used jp NZ opcode to jump over 2-byte instruction.
%2:
	ld	a, #%4
%1:
}

replace {
	jr	Z, %2
	ld	a, #%3
	jr	%1
%2:
	xor	a, a
%1:
} by {
	jr	Z, %2
	ld	a, #%3
	.db	#0x28
	; peephole 169xz used jr Z opcode to jump over 1-byte instruction.
%2:
	xor	a, a
%1:
}

replace {
	jr	NZ, %2
	ld	a, #%3
	jr	%1
%2:
	xor	a, a
%1:
} by {
	jr	NZ, %2
	ld	a, #%3
	.db	#0x20
	; peephole 169xnz used jr NZ opcode to jump over 1-byte instruction.
%2:
	xor	a, a
%1:
}

replace {
	jr	Z, %2
	ld	c, #%3
	jr	%1
%2:
	ld	c, #%4
%1:
} by {
	jr	Z, %2
	ld	c, #%3
	.db	#0xca
	; peephole 170z used jp Z opcode to jump over 2-byte instruction.
%2:
	ld	c, #%4
%1:
}

replace {
	jr	NZ, %2
	ld	c, #%3
	jr	%1
%2:
	ld	c, #%4
%1:
} by {
	jr	NZ, %2
	ld	c, #%3
	.db	#0xc2
	; peephole 170nz used jp NZ opcode to jump over 2-byte instruction.
%2:
	ld	c, #%4
%1:
}

replace {
	jr	Z, %2
	ld	e, #%3
	jr	%1
%2:
	ld	e, #%4
%1:
} by {
	jr	Z, %2
	ld	e, #%3
	.db	#0xca
	; peephole 171z used jp Z opcode to jump over 2-byte instruction.
%2:
	ld	e, #%4
%1:
}

replace {
	jr	NZ, %2
	ld	e, #%3
	jr	%1
%2:
	ld	e, #%4
%1:
} by {
	jr	NZ, %2
	ld	e, #%3
	.db	#0xc2
	; peephole 171nz used jp NZ opcode to jump over 2-byte instruction.
%2:
	ld	e, #%4
%1:
}

replace {
	jr	Z, %2
	ld	l, #%3
	jr	%1
%2:
	ld	l, #%4
%1:
} by {
	jr	Z, %2
	ld	l, #%3
	.db	#0xca
	; peephole 172z used jp Z opcode to jump over 2-byte instruction.
%2:
	ld	l, #%4
%1:
}

replace {
	jr	NZ, %2
	ld	l, #%3
	jr	%1
%2:
	ld	l, #%4
%1:
} by {
	jr	NZ, %2
	ld	l, #%3
	.db	#0xc2
	; peephole 172nz used jp NZ opcode to jump over 2-byte instruction.
%2:
	ld	l, #%4
%1:
}

