// 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 {
	add	ix,sp
} by {
	; peephole 1 removed dead frame pointer setup.
} if notUsed('ix')

replace restart {
	ld	%1, %2 + %3
} by {
	; peephole 2 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 3 made 0 offset explicit.
}

replace restart {
	ld	(iy), %1
} by {
	ld	0 (iy), %1
	; peephole 4 made 0 offset explicit.
}

replace restart {
	dec	hl
} by {
	; peephole 5 removed dead decrement of hl.
} if notUsed('hl')

replace restart {
	ld	%1, %2 (iy)
} by {
	; peephole 6 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 7 removed dead load from %2 (ix) into %1.
} if notUsed(%1)

replace restart {
	ld	%1, %2
	ld	%3, %1
} by {
	; peephole 8 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 9 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	%1, %2 (%3)
	ld	%4, %1
} by {
	; peephole 10 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 11 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 12 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 13 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 14 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 15 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 16 loaded a from (#%1) directly instead of using hl.
} if notUsed('hl')

replace restart {
	ld	hl,#%1 + %2
	ld	a,(hl)
} by {
	; peephole 17 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 18 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 19 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 20 shifted in (%2) instead of a.
}

replace restart {
	ld	%1,(hl)
	ld	a,%2 (%3)
	sub	a,%1
} by {
	ld	a,%2 (%3)
	; peephole 21 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 22 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 23 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 24 loaded #%1 into (hl) instead of (bc).
} if notUsed('a')

replace restart {
	ex	de, hl
	push	de
} by {
	; peephole 25 pushed hl directly instead of going through de.
	push	hl
} if notUsed('de'), notUsed('hl')

replace restart {
	ex	de, hl
	push	bc
	push	de
} by {
	; peephole 26 pushed hl directly instead of going through de.
	push	bc
	push	hl
} if notUsed('de'), notUsed('hl')

replace restart {
	ld	c,l
	ld	b,h
	push	%1
	push	bc
} by {
	; peephole 27 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 28 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 29 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 30 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 31 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 32 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 33 pushed de instead of pushing a twice.
	ld	d,a
	ld	e,#%1
	push	de
} if notUsed('de')

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

replace restart {
	ld	a,#%1
	ld	d,a
} by {
	; peephole 35 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 36 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 37 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 38 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 39 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 40 eleminated dead pop/push pair.
} if notUsed(%1)

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

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

replace restart {
	ld	iy,#%1
	or	a,%2 (iy)
} by {
	; peephole 43 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 44 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 45 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 46 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
	bit	%2,%3 (iy)
} by {
	; peephole 48 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 49 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 50 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 51 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+1
	ld	a, 1 (iy)
	or	a, 0 (iy)
} by {
	ld	hl, #%1
	ld	a, (hl)
	dec	hl
	or	a, (hl)
	; peephole 52 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+1
	add	hl, sp
	ld	a, (hl)
	dec	hl
	or	a, (hl)
	; peephole 53 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 54 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 55 used hl instead of iy.
} if notUsed('iy'), notUsed('hl')

replace restart {
	ld	c,l
	ld	b,h
	inc	bc
} by {
	; peephole 56 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 57 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 58 decremented in (hl) instead of %2 (iy).
	ld	hl, #%1+%2
	dec	(hl)
} if notUsed('hl'), notUsed('iy')

replace restart {
	add	hl, hl
	ld	e, l
	ld	d, h
	inc	de
	inc	de
} by {
	inc	hl
	; peephole 59 incremented once in hl instead of incrementing in de twice.
	add	hl, hl
	ld	e, l
	ld	d, h
} if notUsed('hl')

replace restart {
	add	hl, hl
	inc	hl
	inc	hl
} by {
	inc	hl
	; peephole 60 incremented once in hl instead of incrementing in hl twice.
	add	hl, hl
}

replace restart {
	add	a, a
	add	a, a
	add	a, #0x04
} by {
	inc	a
	; peephole 61 incremented a once instead of adding #0x04 to a.
	add	a, a
	add	a, a
}

replace restart {
	add	hl, hl
	pop	de
	inc	hl
	inc	hl
} by {
	inc	hl
	; peephole 62 incremented once in hl instead of incrementing in hl twice.
	add	hl, hl
	pop	de
}

replace restart {
	ld	a,%1 (%2)
	bit	%3,a
} by {
	; peephole 63 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 64 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 65 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 66 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 (%2)
	res	%3, a
	ld	%1 (%2), a
} by {
	; peephole 67 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 68 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 69 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 70 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 71 removed jp by using inverse jump logic
%1:
} if labelRefCountChange(%1 -1)

replace restart {
	jp	%5
} by {
	jp	%6
	; peephole 72 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 73 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 74 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 77 jumped directly to %3 instead of testing a first.
%1:
	bit	%2,a
	jp	Z,%3
} if labelRefCountChange(%3 +1)

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

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

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

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

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

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

replace restart {
	ld	%1,a
	ld	a,%1
} by {
	ld	%1,a
	; peephole 84 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 85 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 {
	and	a,%1
	or	a,a
} by {
	and	a,%1
	; peephole 86 removed redundant or after and.
}

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

replace {
	ld	%1,%2
	ld	a,%2
} by {
	ld	a,%2
	ld	%1,a
	; peephole 88 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 89 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 90 pushed de
} if notUsed('a')

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 91 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
} by {
}

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


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

replace restart {
	ld	c,l
	ld	b,h
	ld	hl,#%1
	add	hl,bc
} by {
	; peephole 98 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 99 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 100 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 101 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 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 {
	ld	(hl),#0x00
	inc	hl
	ld	(hl),#0x00
} by {
	xor	a, a
	; peephole 105 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 106 moved increment of hl to constant.
}

replace restart {
	call    %1
	ret
} by {
	jp  %1
	; peephole 107 replaced call at end of function by jump (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 108 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 109 used #%1 from hl for load into de.
	ld	hl,#%1
	ld	e,l
	ld	d,h
}

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

replace restart {
	ld	%1,a
	bit	%2,%1
} by {
	bit	%2,a
	; peephole 113 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 114 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 115 used value still in a instead of reloading from %1.
}

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

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

replace restart {
	or	a,%1
	jp	NZ,%2
	xor	a,a
	jp	%3
} by {
	or	a,%1
	jp	NZ,%2
	; peephole 118 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 119 used ex to load hl into de.
	ex	de,hl
} if notUsed('hl')

replace restart {
	ld	l,e
	ld	h,d
} by {
	; peephole 120 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 121 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 123 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 124 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 125 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 126 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 127 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 128 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 129 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 130 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 131 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 132 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 122 replaced jump by return.
} if labelIsReturnOnly(%5), labelRefCountChange(%5 -1)

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

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

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

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

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

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

