// Due to major changes in the Z80 peepholes the old peepholes from peeph.def have been moved here.
// All new peepholes went into peeph-z80.def. A GBZ80 expert should look into this files and peeph-z80.def
// And move peepholes that are useful and correct for both Z80 and GBZ80 into peeph.def.

// peeph.def - Common Z80 and gbz80 peephole rules
//
//
// (c) Philipp Klaus Krause (pkk@spth.de, philipp@colecovision.eu) 2006 - 2007
//
// 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)

replace restart {
	ldhl	sp,#%1
	dec	hl
} by {
	; peephole 2 combined ld and dec.
	ldhl	sp,#(%1 - 1)
}

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 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 8 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 9 eliminated jump.
%2:
%1:
} if labelRefCountChange(%1 -1)

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

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

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

replace restart {
	ld	%1,a
	ld	a,%1
} by {
	ld	%1,a
	; peephole 13 removed redundant load from %1 into a.
} if notVolatile(%1), notSame(%1 '(hl+)'), notSame(%1 '(hl-)')

replace restart {
	ld	a,%1
	ld	%1,a
} by {
	ld	a,%1
	; peephole 14 removed redundant load from a into %1.
} if notVolatile(%1), notSame(%1 '(hl+)'), notSame(%1 '(hl-)')

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

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

replace restart {
	ld	%1,a
	and	a,%2
	ld	%1,a
} by {
	; peephole 17 removed redundant load into %1.
	and	a,%2
	ld	%1,a
} if notVolatile(%1)

replace {
	ld	%1,%2
	ld	a,%2
} by {
	ld	a,%2
	ld	%1,a
	; peephole 18 loaded value in a first and used it next
} if notVolatile(%1 %2), canAssign(%1 'a'), operandsNotRelated(%1 %2)

replace restart {
	ld	%1,%2
	ld	%3,%4
	ld	%2,%1
	ld	%4,%3
} by {
	ld	%1,%2
	ld	%3,%4
	; peephole 19 removed redundant load from %3%1 into %4%2
} if notVolatile(%1 %2 %3 %4)

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 20 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 21 removed load by replacing sub with cp
	assert	a=%1
}

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

replace restart {
	rlca
	ld	a,#0x00
	rla
} by {
	rlca
	and	a,#0x01
	; peephole 22 replaced zero load, rla by and since rlca writes the same value to carry bit and least significant bit.
}

replace restart {
	add	a,#0x00
	ld	%2,a
	ld	a,%3
	adc	a,%4
} by {
	; peephole 23 removed lower part of multibyte addition.
	ld	%2,a
	ld	a,%3
	add	a,%4
}

replace restart {
	or	a,%1
	jp	NZ,%2
	ld	%3,#0x00
} by {
	or	a,%1
	jp	NZ,%2
	ld	%3,a
	; peephole 24 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 25 replaced constant #0x00 by a (which has just been tested to be #0x00).
}

replace restart {
	ld	bc,#%1 + %2
	inc	bc
	inc	bc
	inc	bc
} by {
	ld	bc,#%1 + %2 + 3
	; peephole 26 moved triple increment of bc to constant.
}

replace restart {
	ld	bc,#%1 + %2
	inc	bc
	inc	bc
} by {
	ld	bc,#%1 + %2 + 2
	; peephole 27 moved double increment of bc to constant.
}

replace restart {
	ld	bc,#%1 + %2
	inc	bc
} by {
	ld	bc,#%1 + %2 + 1
	; peephole 28 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 29 moved addition of constant 0x%3%2 to bc to constant.
}

replace restart {
	ld	bc,#%1 + %4
	ld	a,c
	add	a,#0x%2
	ld	c,a
	ld	a,b
	adc	a,#0x%3
	ld	b,a
} by {
	ld	bc,#%1 + %4 + 0x%3%2
	; peephole 30 moved addition of constant 0x%3%2 to bc to constant.
}

replace restart {
	call	%1
	ret
} by {
	jp	%1
	; peephole 31 replaced call at end of function by jump.
}

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)

barrier

// Should be one of the last ones. Opens the code to further peephole optimization.
replace restart {
%1:
} by {
	; peephole 32 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	%5
} by {
	jr	%5
	; peephole 153 changed absolute to relative unconditional jump.
} if labelInRange(%5)

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

barrier

// Do not try further peephole optimization after these, as other peepholes e.g. might try to generate add a, (hl-), etc otherwise.

replace {
	ld	a, (hl)
	inc	hl
} by {
	ld	a, (hl+)
	; peephole GB1 used ldi to increment hl after load
}

replace {
	ld	a, (hl)
	dec	hl
} by {
	ld	a, (hl-)
	; peephole GB2 used ldd to decrement hl after load
}

replace {
	ld	(hl), a
	inc	hl
} by {
	ld	(hl+), a
	; peephole GB3 used ldi to increment hl after load
}

replace {
	ld	(hl), a
	dec	hl
} by {
	ld	(hl-), a
	; peephole GB4 used ldd to decrement hl after load
}

replace {
	inc hl
	dec hl
} by {
	; peephole GB5 removed inc hl / dec hl pair
}

replace {
	ld	(hl), a
	inc	de
	ld	a, (de)
	inc	hl
} by {
	ld	(hl+), a
	; peephole GB6 used ldi to increment hl
	inc	de
	ld	a, (de)
}

replace {
	ld	a, (hl)
	ld	(bc), a
	inc	bc
	inc	hl
} by {
	ld	a, (hl+)
	; peephole GB7 used ldi to increment hl
	ld	(bc), a
	inc	bc
}

