struct / union in initializer, RFE #901.
[sdcc.git] / sdcc / src / z80 / peeph.def
blob0f23c2f0e87df3c7829034fda34d0de135da3841
1 // peeph.def - Common Z80 and sm83 peephole rules
2 //
3 // (c) Philipp Klaus Krause (pkk@spth.de, philipp@colecovision.eu) 2006 - 2021
4 // (c) Sebastian 'basxto' Riedel (sdcc@basxto.de) 2020 - 2022
5 //
6 // This program is free software; you can redistribute it and/or modify it
7 // under the terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 2, or (at your option) any
9 // later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 replace restart {
21 ld %1, %1
22 } by {
23 ; common peephole 0a removed redundant load from %1 into %1.
24 } if notVolatile(%1)
26 //TODO: works for the other ports, but slows at least some of them down
27 replace restart {
28 ld %2, %1
29 ld %3, %4
30 ld %1, %2
31 } by {
32 ld %2, %1
33 ld %3, %4
34 ; common peephole 0b removed redundant load from %2 back into %1.
35 }if isPort('sm83'), notSame(%1 '(hl+)' '(hl-)'), notSame(%2 '(hl+)' '(hl-)'), operandsNotRelated(%3 %1), operandsNotRelated(%3 %2), notVolatile(%1), notVolatile(%2),
37 replace restart {
38 ld %1, %2
39 } by {
40 ; common peephole 1 removed dead load from %2 into %1.
41 } if notVolatile(%1), notUsed(%1), notVolatile(%2), notSame(%1 '(hl+)' '(hl-)'), notSame(%2 '(hl+)' '(hl-)')
43 replace restart {
44 %1 hl, %2
45 } by {
46 ; common peephole 2a removed %1 hl, %2 due to unused result.
47 } if same(%1 'adc' 'sbc'), notUsed('hl' 'f')
49 replace restart {
50 add hl, %2
51 } by {
52 ; common peephole 2b removed add hl, %2 due to unused result.
53 } if notUsed('hl' 'cf' 'nf')
55 replace restart {
56 %1 %2
57 } by {
58 ; common peephole 2c removed %1 %2 due to unused result.
59 } if same(%1 'dec' 'inc'), same(%2 'bc' 'de' 'hl' 'sp' 'ix' 'iy'), notUsed(%2)
61 replace restart {
63 } by {
64 ; common peephole 2d removed %1 due to unused result.
65 } if same(%1 'rlca' 'rla' 'rrca' 'rra'), notUsed('a' 'hf' 'nf' 'cf')
67 replace restart {
68 ld %1, %2 + %3
69 } by {
70 ; common peephole 3 removed dead load from %2 + %3 into %1.
71 } if notVolatile(%1), notUsed(%1), notSame(%1 '(hl+)' '(hl-)')
72 // Should probably check for notVolatile(%2), too, but gives many false positives and no regression tests fail.
74 replace restart {
75 adc hl, hl
76 adc hl, hl
77 } by {
78 add hl, hl
79 add hl, hl
80 ; common peephole 3a replaced adc by add since l is unused.
81 } if notUsed('l' 'zf')
83 replace restart {
84 adc hl, hl
85 } by {
86 add hl, hl
87 ; common peephole 3b replaced adc by add since l is unused.
88 } if notUsed('l' 'zf')
90 replace restart {
91 ld %1, (%2)
92 } by {
93 ld %1, 0 (%2)
94 ; common peephole 4a made 0 offset explicit.
95 } if same(%2 'ix' 'iy')
97 replace restart {
98 ld (%1), %2
99 } by {
100 ld 0 (%1), %2
101 ; common peephole 4b made 0 offset explicit.
102 } if same(%1 'ix' 'iy')
104 //remove dead INC/DEC instructions on 16-bit registers
105 replace restart {
106 %1 %2
107 } by {
108 ; common peephole 5 removed dead %1 %2.
109 } if same(%1 'inc' 'dec'), same(%2 'bc' 'de' 'hl' 'sp' 'ix' 'iy'), notUsed(%2)
111 //remove dead INC/DEC instructions on 8-bit registers
112 replace restart {
113 %1 %2
114 } by {
115 ; common peephole 6a removed dead %1 %2
116 } if same(%1 'inc' 'dec'), same(%2 'a' 'b' 'c' 'd' 'e' 'h' 'l' 'ixh' 'ixl' 'iyh' 'iyl'), notUsed(%2 'f')
118 //remove dead ALU instructions on 8-bit register
119 replace restart {
120 %1 a, %2
121 } by {
122 ; common peephole 6b removed dead %1 a, %2
123 } if same(%1 'sub' 'sbc' 'add' 'adc' 'and' 'or' 'xor'), notUsed('af')
125 //remove dead CP instructions
126 replace restart {
127 cp a, %1
128 } by {
129 ; common peephole 6c removed dead cp a, %1
130 } if notUsed('f')
132 replace restart {
133 %1 %2
134 } by {
135 ; common peephole 6d removed dead %1 %2
136 } if same(%1 'rlc' 'rl' 'rrc' 'rr' 'sla' 'sra' 'srl' 'sll' 'sli'), notVolatile(%2), notUsed(%2 'f')
138 replace restart {
139 ld %1, %2 (%3)
140 } by {
141 ; common peephole 7 removed dead load from %2 (%3) into %1.
142 } if notUsed(%1), same(%3 'ix' 'iy')
143 // Should probably check for notVolatile(), but gives many false positives and no regression tests fail.
145 replace {
146 ex de, hl
147 ex de, hl
148 } by {
149 ; common peephole 8 removed double de/hl swap.
152 replace restart {
153 ld %1, %2
154 ld %3, %1
155 } by {
156 ; common peephole 9 loaded %3 from %2 directly instead of going through %1.
157 ld %3, %2
158 } if canAssign(%3 %2), notVolatile(%1), notUsed(%1), notSame(%3 '(hl)' '(de)' '(bc)' '(hl+)' '(hl-)'), notSame(%1 '(hl+)' '(hl-)')
160 replace restart {
161 ld %1, %2
162 ld %3, %1
163 } by {
164 ; common peephole 9a loaded %3 from %2 directly instead of going through %1.
165 ld %3, %2
166 } if canAssign(%3 %2), notVolatile(%1), notUsed(%1), canAssign('a' %1), notSame(%1 '(hl+)' '(hl-)'), operandsNotRelated(%1 %3)
168 replace restart {
169 ld %1, hl
170 ld hl, %1
171 } by {
172 ; common peephole 9b reused value still in hl.
173 ld %1, hl
174 } if notVolatile(%1), notSame(%1 '(hl+)' '(hl-)')
176 replace restart {
177 ld %1, %2
178 ld %3, %4
179 ld %5, %1
180 } by {
181 ld %5, %2
182 ; common peephole 10 loaded %5 from %2 directly instead of going through %1.
183 ld %3, %4
184 } if canAssign(%5 %2), notVolatile(%1), operandsNotRelated(%1 %4), operandsNotRelated(%1 %3), operandsNotRelated(%3 %5), operandsNotRelated(%4 %5), notUsed(%1), notSame(%3 %4 '(hl)' '(de)' '(bc)' '(hl+)' '(hl-)'),
185 notVolatile(%5), notSame(%1 '(hl+)' '(hl-)'), notSame(%5 '(hl+)' '(hl-)')
186 // Rule OK unless both %5 and %4 are volatile, but we can't express that directly.
188 replace restart {
189 ld %3 (ix), %1
190 ld %4 (ix), %2
191 ld %5, %3 (ix)
192 ld %6, %4 (ix)
193 } by {
194 ld %3 (ix), %1
195 ld %4 (ix), %2
196 ; common peephole 11 loaded %5%6 from %1%2 directly instead of going through %3 (ix) %4 (ix).
197 ld %5, %1
198 ld %6, %2
199 } if canAssign(%5 %1), canAssign(%6 %2), notSame(%5 %2)
201 replace restart {
202 ld %1, %2 (%3)
203 ld %4, %1
204 } by {
205 ; common peephole 12 loaded %2 (%3) into %4 directly instead of going through %1.
206 ld %4, %2 (%3)
207 } if canAssign(%4 %2 %3), notVolatile(%1), notUsed(%1)
209 replace restart {
210 ld %1, %2
211 ld %3 (%4), %1
212 } by {
213 ; common peephole 13 loaded %2 into %3 (%4) directly instead of going through %1.
214 ld %3 (%4), %2
215 } if canAssign(%3 %4 %2), notVolatile(%1), notUsed(%1), canAssign('a' %1)
216 // canAssign ('a' %1) checks that %1 is an 8-bit value
218 replace restart {
219 ld %1, %2 (%3)
220 ld %4, %5 (%6)
221 ld %7, %1
222 } by {
223 ld %7, %2 (%3)
224 ; common peephole 14 loaded %2 (%3) into %7 directly instead of going through %1.
225 ld %4, %5 (%6)
226 } if canAssign(%7 %2 %3), notVolatile(%1), notUsed(%1), notSame(%1 %4), notSame(%7 %4)
228 replace restart {
229 ld %1, %2 (%3)
230 ld %4, %5
231 ld %7, %1
232 } by {
233 ld %7, %2 (%3)
234 ; common peephole 15 loaded %2 (%3) into %7 directly instead of going through %1.
235 ld %4, %5
236 } if canAssign(%7 %2 %3), notVolatile(%1), notUsed(%1), operandsNotRelated(%1 %5), operandsNotRelated(%7 %4), operandsNotRelated(%7 %5), notSame(%4 '(hl)' '(de)' '(bc)' '(hl+)' '(hl-)'), notSame(%5 '(hl)' '(de)' '(bc)' '(hl+)' '(hl-)' '(iy)')
238 replace restart {
239 ld %1,#%2
240 ld a,%3 (%1)
241 } by {
242 ; common peephole 16 loaded %2 into a directly instead of going through %1.
243 ld a,(#%2 + %3)
244 } if notUsed(%1)
246 replace restart {
247 ld hl, #%1
248 ld a, (hl)
249 } by {
250 ld a, (#%1)
251 ; common peephole 17 loaded a from (#%1) directly instead of using hl.
252 } if notUsed('hl')
254 replace restart {
255 ld hl,#%1 + %2
256 ld a,(hl)
257 } by {
258 ; common peephole 18 loaded %2 into a directly instead of using hl.
259 ld a, (#%1 + %2)
260 } if notUsed('hl')
262 replace restart {
263 ld hl,#%1
264 ld (hl),a
265 } by {
266 ld (#%1),a
267 ; common peephole 19 loaded (#%1) from a directly instead of using hl.
268 } if notUsed('hl')
270 replace restart {
271 ld hl,#%1 + %2
272 ld (hl),a
273 } by {
274 ld (#%1 + %2),a
275 ; common peephole 20 loaded (#%1) from a directly instead of using hl.
276 } if notUsed('hl')
278 replace restart {
279 ld a, %1 (%2)
280 %3 a
281 ld %1 (%2), a
282 } by {
283 %3 %1 (%2)
284 ld a, %1 (%2)
285 ; common peephole 21 shifted in (%2) instead of a.
286 } if same(%3 'srl' 'sla' 'rl' 'rr' 'rlc' 'rrc' 'sll')
288 replace restart {
289 ld %1,(hl)
290 ld a,%2 (%3)
291 %4 a,%1
292 } by {
293 ld a,%2 (%3)
294 ; common peephole 22 used (hl) in %4 directly instead of going through %1.
295 %4 a,(hl)
296 } if notVolatile(%1), notUsed(%1), same(%4 'add' 'adc' 'sub' 'sbc' 'and' 'or' 'xor')
298 replace restart {
299 ld l, %1
300 ld h, %2
301 ld a, (hl)
302 inc hl
303 ld h, (hl)
304 ld l, a
305 } by {
306 ld a, (%3)
307 ld l, a
308 inc %3
309 ld a, (%3)
310 ld h, a
311 ; common peephole 23 optimize 16-bit load from %3.
312 } if canJoinRegs(%2 %1 %3), notUsed(%3 'a')
314 replace restart {
315 inc %1
316 ld l, %2
317 ld h, %3
318 } by {
319 ld l, %2
320 ld h, %3
321 ; common peephole 24 incremented in hl instead of %1.
322 inc hl
323 } if canJoinRegs(%3 %2 %4), same(%1 %4), notUsed(%1)
325 replace restart {
326 ld %1, l
327 ld %2, h
328 ld a, #%3
329 ld (%4), a
330 } by {
331 ld %1, l
332 ld %2, h
333 ld (hl), #%3
334 ; common peephole 25a loaded #%1 into (hl) instead of (%4).
335 } if canJoinRegs(%2 %1 %5), same(%4 %5), notUsed('a')
337 replace restart {
338 ld %1, %6
339 ld %2, %7
340 ld a, #%3
341 ld (%4), a
342 } by {
343 ld %1, %6
344 ld %2, %7
345 ld a, #%3
346 ld (%8), a
347 ; common peephole 25b loaded #%1 into (%8) instead of (%4).
348 } if canJoinRegs(%2 %1 %5), same(%4 %5), canJoinRegs(%7 %6 %8)
350 replace restart {
351 push %1
352 ex (sp), %2
353 } by {
354 ; common peephole 26a merged push and ex (sp), since %2 isn't used.
355 push %2
356 } if same(%2 'hl' 'ix' 'xy'), notUsed(%2)
358 replace restart {
359 push de
360 ex de, hl
361 } by {
362 ; common peephole 26b moved push after de/hl swap.
363 ex de, hl
364 push hl
367 replace restart {
368 push hl
369 ex de, hl
370 } by {
371 ; common peephole 26c moved push after de/hl swap.
372 ex de, hl
373 push de
376 replace restart {
377 ex de, hl
378 push %1
379 } by {
380 ; common peephole 26d moved push %1 before de/hl swap.
381 push %1
382 ex de, hl
383 } if notSame(%1 'hl' 'de')
385 replace restart {
386 ex de, hl
387 push de
388 } by {
389 ; common peephole 26e pushed hl directly instead of going through de.
390 push hl
391 } if notUsed('de' 'hl')
393 replace restart {
394 ld l,%1
395 ld h,d
396 push hl
397 } by {
398 ; common peephole 27 pushed de instead of hl removing a load.
399 ld e,%1
400 push de
401 } if notUsed('hl' 'e')
403 //TODO: remove if unused
404 replace restart {
405 ex de, hl
406 push %1
407 push de
408 } by {
409 ; common peephole 28 pushed hl directly instead of going through de.
410 push %1
411 push hl
412 } if notSame(%1 'hl' 'de'), notUsed('de' 'hl')
414 replace restart {
415 ld %4,%1
416 ld %5,%2
417 push %6
418 } by {
419 ; common peephole 29 pushed %3 directly instead of going through %6.
420 push %3
421 } if canJoinRegs(%2 %1 %3), canJoinRegs(%5 %4 %7), same(%7 %6), notUsed(%6)
423 replace restart {
424 ld %2,%5
425 ld %3,%6
426 push %1
427 push %4
428 } by {
429 ; common peephole 30 pushed %7 directly instead of going through %4.
430 push %1
431 push %7
432 } if canJoinRegs(%3 %2 %5), same(%5 %4), canJoinRegs(%6 %5 %7), notSame(%1 %4), notUsed(%4)
434 replace restart {
435 pop %1
436 ld %2, %3
437 ld %4, %5
438 } by {
439 ; common peephole 31 popped %6 directly instead of going through %1.
440 pop %6
441 } if canJoinRegs(%4 %2 %6), canJoinRegs(%5 %3 %7), same(%7 %1), notUsed(%1)
443 replace restart {
444 ex de, hl
445 ld e, l
446 ld d, h
447 } by {
448 ; common peephole 32a removed de/hl swap.
449 ld l, e
450 ld h, d
453 replace restart {
454 ex de, hl
455 ld l, e
456 ld h, d
457 } by {
458 ; common peephole 32b removed de/hl swap.
459 ld e, l
460 ld d, h
463 replace restart {
464 ld %1 (%4), %2
465 ld %3, %1 (%4)
466 } by {
467 ; common peephole 33 loaded %3 from %2 instead of going through %1 (%4).
468 ld %1 (%4), %2
469 ld %3, %2
470 } if same(%4 'ix' 'iy'), canAssign(%3 %2), notSame(%3 'bc' 'de' 'hl' 'ix' 'iy')
471 // Don't need to check for volatile, since ix is used for the stack.
473 replace restart {
474 ld %1 (%3), a
475 push %4
476 ld %2, %1 (%3)
477 } by {
478 ld %1 (%3), a
479 push %4
480 ; common peephole 34 loaded %2 from a instead of %1 (%3)
481 ld %2, a
482 } if same(%3 'ix' 'iy'), canAssign(%2 'a')
484 replace restart {
485 push af
486 inc sp
487 ld a,e
488 push af
489 inc sp
490 } by {
491 ; common peephole 35 pushed de instead of pushing a twice.
492 ld d,a
493 push de
494 } if notUsed('d'), notUsed('a')
496 replace restart {
497 pop %1
498 pop %2
499 push %2
500 push %1
501 ld a, #%3
502 ld (%2), a
503 } by {
504 ; common peephole 36 used hl instead of %2.
505 pop %1
506 pop hl
507 push hl
508 push %1
509 ld (hl), #%3
510 } if notUsed('hl' %2)
512 replace restart {
513 push af
514 inc sp
515 ld a, #%1
516 push af
517 inc sp
518 } by {
519 ; common peephole 37a pushed %4 instead of pushing a twice.
520 ld %2, a
521 ld %3, #%1
522 push %4
523 } if unusedReg(%4 'bc' 'de' 'hl'), canSplitReg(%4 %2 %3), notUsed('a')
525 replace restart {
526 push af
527 inc sp
528 xor a, a
529 push af
530 inc sp
531 } by {
532 ; common peephole 37b pushed %4 instead of pushing a twice.
533 ld %2, a
534 ld %3, #0x00
535 push %4
536 } if unusedReg(%4 'bc' 'de' 'hl'), canSplitReg(%4 %2 %3), notUsed('af')
538 replace restart {
539 push %1
540 inc sp
541 push %2
542 inc sp
543 } by {
544 ld %4, %5
545 ; common peephole 38 combined pushing of %3 and %5.
546 push %1
547 } if canSplitReg(%1 %3 %4), canSplitReg(%2 %5), canAssign(%4 %5), notUsed(%4)
549 replace restart {
550 ld hl, #%1
551 add hl, %2
552 } by {
553 ; common peephole 39 replaced 16-bit addition by 8-bit loads and 16-bit increment.
554 ld l, %4
555 ld h, %3
556 inc hl
557 } if canSplitReg(%2 %3 %4), immdInRange(1 1 '+' %1 0 %9)
559 replace restart {
560 and a, #%1
561 and a, #%2
562 } by {
563 ; common peephole 40a combined redundant ANDs #%1 and #%2.
564 and a, #%3
565 } if operandsLiteral(%1 %2), immdInRange(0x00 0xFF '&' %1 %2 %x3)
567 replace restart {
568 or a, #%1
569 or a, #%2
570 } by {
571 ; common peephole 40b combined redundant ORs #%1 and #%2.
572 or a, #%3
573 } if operandsLiteral(%1 %2), immdInRange(0x00 0xFF '|' %1 %2 %x3)
575 replace restart {
576 ld %1, %2
577 ld %1, %3
578 } by {
579 ; common peephole 41a remove double load to %1.
580 ld %1, %3
581 } if notVolatile(%1), notVolatile(%2), notSame(%1 '(hl+)' '(hl-)'), notSame(%2 '(hl+)' '(hl-)'), operandsNotRelated(%1 %3)
583 replace restart {
584 push af
585 inc sp
586 ld a, c
587 push af
588 inc sp
589 } by {
590 ld b, a
591 ; common peephole 42 combined pushing of a and c.
592 push bc
593 } if notUsed('b'), notUsed('a')
595 replace restart {
596 push %1
597 inc sp
598 ld a, %2
599 push af
600 inc sp
601 } by {
602 ld %4, %2
603 ; common peephole 43 combined pushing of %3 and %2.
604 push %1
605 } if notSame(%1 'iy'), canSplitReg(%1 %3 %4), canAssign(%4 %2), notUsed(%4 'a')
607 replace restart {
608 ld a, %1
609 push af
610 inc sp
611 ld a, %2 (%3)
612 push af
613 inc sp
614 } by {
615 ld %4, %1
616 ld %5, %2 (%3)
617 ; common peephole 44a combined pushing of %1 and %2 (%3).
618 push %6
619 } if unusedReg(%6 'bc' 'de' 'hl'), canSplitReg(%6 %4 %5), canAssign(%4 %1), notUsed('a')
621 replace restart {
622 ld a, (%1)
623 push af
624 inc sp
625 ld a, (%2)
626 push af
627 inc sp
628 } by {
629 ld a, (%1)
630 ld %4, a
631 ld a, (%2)
632 ld %5, a
633 ; common peephole 44b combined pushing of (%1) and (%2).
634 push %6
635 } if unusedReg(%6 'bc' 'de' 'hl'), notSame(%6 %1 %2), canSplitReg(%6 %4 %5)
637 replace restart {
638 ld %1, #%2
639 } by {
640 ; common peephole 45 replace 16-bit immediate load by 8-bit one.
641 ld %3, #%4
642 } if canSplitReg(%1 %5 %3), immdInRange(0x00 0xff '&' %2 0xff %4), canAssign(%3 %4), notUsed(%5)
644 replace restart {
645 ld %1, #%2
646 } by {
647 ; common peephole 46 replace 16-bit immediate load by 8-bit one.
648 ld %3, #%4
649 } if canSplitReg(%1 %3 %5), immdInRange(0x00 0xff '/' %2 256 %4), canAssign(%3 %4), notUsed(%5)
651 replace restart {
652 ld a, %1 (%3)
653 push af
654 inc sp
655 ld a, %2 (%3)
656 push af
657 inc sp
658 } by {
659 ; common peephole 47a pushed %1 (%3), %2 (%3) through %6 instead of af.
660 ld %4, %1 (%3)
661 ld %5, %2 (%3)
662 push %6
663 } if unusedReg(%6 'bc' 'de' 'hl'), canSplitReg(%6 %4 %5), notUsed('a')
665 replace restart {
666 ld a, (hl)
667 push af
668 inc sp
669 %1 hl
670 ld a, (hl)
671 push af
672 inc sp
673 } by {
674 ; common peephole 47b pushed (hl), %1, (hl) through %4 instead of af.
675 ld a, (hl)
676 %1 hl
677 ld %2, a
678 ld a, (hl)
679 ld %3, a
680 push %4
681 } if same(%1 'inc' 'dec'), unusedReg(%4 'bc' 'de'), canSplitReg(%4 %2 %3), notUsed('a')
683 replace restart {
684 ld a, (%5)
685 push af
686 inc sp
687 ld a, (%6)
688 push af
689 inc sp
690 } by {
691 ; common peephole 47c pushed (%5), (%6) through %4 instead of af.
692 ld a, (%5)
693 ld %2, a
694 ld a, (%6)
695 ld %3, a
696 push %4
697 } if same(%5 'hl' 'hl+' 'hl-'), same(%6 'hl' 'hl+' 'hl-'), unusedReg(%4 'bc' 'de'), canSplitReg(%4 %2 %3)
699 replace restart {
700 ld %1, %4
701 ld %2, %5
702 push %3
703 } by {
704 ; common peephole 48 pushed %6 instead of %3.
705 push %6
706 } if canJoinRegs(%2 %1 %7), same(%3 %7), canJoinRegs(%5 %4 %6), notUsed(%3)
708 replace restart {
709 ld a, (hl)
710 %4 hl
711 ld h, (hl)
712 ld l, a
713 push hl
714 } by {
715 ; common peephole 49 pushed %3 instead of hl.
716 ld %1, (hl)
717 %4 hl
718 ld %2, (hl)
719 push %3
720 } if same(%4 'inc' 'dec'), unusedReg(%3 'de' 'bc'), canSplitReg(%3 %2 %1), notUsed('hl')
722 replace restart {
723 ld %3, %1
724 push %3
725 } by {
726 ; common peephole 49a pushed %2 instead of %3.
727 ld %2, %1
728 push %2
729 } if same(%3 'ix' 'iy'), notUsed(%3), unusedReg(%2 'bc' 'de' 'hl'), canAssign(%2 %1)
731 replace restart {
732 pop %1
733 push %1
734 } by {
735 ; common peephole 50a eliminated dead pop/push %1 pair.
736 } if notUsed(%1)
738 replace restart {
739 push %1
740 pop %1
741 } by {
742 ; common peephole 50b eliminated dead push/pop pair.
745 replace restart {
746 push %1
747 inc sp
748 inc sp
749 } by {
750 ; common peephole 50c eliminated dead push/inc sp pair.
753 replace restart {
754 pop %1
755 ld %2 (ix), %3
756 push %1
757 } by {
758 ; common peephole 51 eliminated dead pop/push %1 pair.
759 ld %2 (ix), %3
760 } if notUsed(%1), operandsNotRelated(%1 %3)
762 replace restart {
763 pop %1
764 ld %2, %3
765 push %1
766 } by {
767 ; common peephole 51a eliminated dead pop/push %1 pair.
768 ld %2, %3
769 } if notUsed(%1), operandsNotRelated(%1 %3), operandsNotRelated(%1 %2)
771 replace restart {
772 push %1
773 pop %2
774 } by {
775 ld %6, %4
776 ld %5, %3
777 ; common peephole 52a replaced push/pop pair by loads.
778 } if canSplitReg(%1 %3 %4), canSplitReg(%2 %5 %6), notSame(%1 %2 'ix' 'iy'), notUsed(%1)
780 replace restart {
781 push %1
782 pop af
783 } by {
784 ld a, %3
785 ; common peephole 52b replaced push/pop pair by load.
786 } if canSplitReg(%1 %3 %4), notUsed('f')
788 replace restart {
789 push %1
790 ld %1, %7
791 pop %2
792 } by {
793 ld %6, %4
794 ld %5, %3
795 ld %1, %7
796 ; common peephole 52c replaced push/pop pair by loads.
797 } if canSplitReg(%1 %3 %4), canSplitReg(%2 %5 %6), notSame(%1 %2 'ix' 'iy'), operandsNotRelated(%7 %1)
799 replace restart {
800 ld %3, #%1
801 ld %4, %2 (%3)
802 } by {
803 ; common peephole 53 used direct memory loading instead of indirect.
804 ld a, (#%1 + %2)
805 ld %4, a
806 } if notUsed(%3 'a')
808 replace restart {
809 ld %4, #%1
810 %3 %5, %2 (%4)
811 } by {
812 ; common peephole 54 used hl instead of %4.
813 ld hl, #%1 + %2
814 %3 %5, (hl)
815 } if notUsed(%4 'hl'), same(%5 'a' 'b' 'c' 'd' 'e' 'h' 'l'), same(%3 'add' 'adc' 'and' 'ld' 'or' 'sbc' 'sub' 'xor')
817 replace restart {
818 ld %4, #%1
819 ld l, %3 (%4)
820 } by {
821 ; common peephole 55l used hl instead of %4.
822 ld hl, #%1 + %3
823 ld l, (hl)
824 } if notUsed(%4 'h')
826 replace restart {
827 ld %4, #%1
828 ld h, %3 (%4)
829 } by {
830 ; common peephole 55 used hl instead of %4.
831 ld hl, #%1 + %3
832 ld h, (hl)
833 } if notUsed(%4 'l')
835 replace restart {
836 ld %4, #%1
837 ld %2 (%4), %3
838 } by {
839 ; common peephole 56 used hl instead of %4.
840 ld hl, #%1 + %2
841 ld (hl), %3
842 } if notUsed(%4 'hl'), notSame(%3 'h' 'l')
844 replace restart {
845 ld %4, #%1
846 ld %2 (%4), %3
847 } by {
848 ; common peephole 57 used direct memory storing instead of indirect.
849 ld a, %3
850 ld (#%1 + %2), a
851 } if notUsed('a' %4)
853 replace restart {
854 ld %4, #%1
855 ld %2, %5 (%4)
856 ld %3, %6 (%4)
857 } by {
858 ; common peephole 58 used hl instead of %4.
859 ld hl, #%1 + %5
860 ld %2, (hl)
861 inc hl
862 ld %3, (hl)
863 } if operandsNotRelated(%2 'hl'), operandsNotRelated(%3 'hl'), immdInRange(-128 127 '+' %5 1 %7), same(%6 %7), notUsed(%4 'hl')
865 replace restart {
866 ld %4, #%1
867 ld %2 (%4), %3
868 ld l, %2 (%4)
869 } by {
870 ; common peephole 59 used hl instead of %4.
871 ld hl, #%1 + %2
872 ld (hl), %3
873 ld l, (hl)
874 } if notUsed(%4 'h')
876 replace restart {
877 ld %3, #%1
878 ld %2 (%3), %4
879 } by {
880 ; common peephole 60 used hl instead of %3.
881 ld hl, #%1 + %2
882 ld (hl), %4
883 } if notUsed(%3 'hl'), operandsNotRelated(%4 'hl')
885 replace restart {
886 ld %4, #%1
887 %5 %2, %3 (%4)
888 } by {
889 ; common peephole 61 used hl instead of %4.
890 ld hl, #%1 + %3
891 %5 %2, (hl)
892 } if same(%5 'bit' 'res' 'set'), notUsed(%4 'hl')
894 replace restart {
895 ld %4, #%1
896 add %4, sp
897 ld %2, %5 (%4)
898 ld %3, %6 (%4)
899 } by {
900 ; common peephole 62 used hl instead of %4.
901 ld hl, #%1 + %5
902 add hl, sp
903 ld %2, (hl)
904 inc hl
905 ld %3, (hl)
906 } if operandsNotRelated(%2 'hl'), immdInRange(-128 127 '+' %5 1 %7), same(%7 %6), notUsed(%4 'hl')
908 replace restart {
909 ld %4, #%1
910 add %4, sp
911 ld %2, %3 (%4)
912 } by {
913 ; common peephole 63 used hl instead of %4.
914 ld hl, #%1 + %3
915 add hl, sp
916 ld %2, (hl)
917 } if notUsed(%4 'hl')
919 replace restart {
920 ld %4, #%1
921 add %4, sp
922 ld l, %2 (%4)
923 ld h, %3 (%4)
924 } by {
925 ; common peephole 64 used hl instead of %4.
926 ld hl, #%1 + %2
927 add hl, sp
928 ld a, (hl)
929 inc hl
930 ld h, (hl)
931 ld l, a
932 } if immdInRange(-128 127 '+' %2 1 %5), same(%5 %3), notUsed(%4 'a')
934 replace restart {
935 ld %4, #%1
936 add %4, sp
937 ld %5 (iy), #%2
938 ld %6 (iy), #%3
939 } by {
940 ; common peephole 65 used hl instead of %4.
941 ld hl, #%1 + %5
942 add hl, sp
943 ld (hl), #%2
944 inc hl
945 ld (hl), #%3
946 } if immdInRange(-128 127 '+' %5 1 %7), same(%7 %6), notUsed(%4 'hl')
948 replace restart {
949 ld %4, #%1
950 add %4, sp
951 ld a, %2 (%4)
952 or a, %3 (%4)
953 } by {
954 ld hl, #%1 + %2
955 add hl, sp
956 ld a, (hl)
957 inc hl
958 or a, (hl)
959 ; common peephole 66a used hl instead of %4.
960 } if immdInRange(-128 127 '+' %2 1 %5), same(%5 %3), notUsed(%4 'hl')
962 replace restart {
963 ld %4, #%1
964 add %4, sp
965 ld a, %2 (%4)
966 or a, %3 (%4)
967 } by {
968 ld hl, #%1 + %3
969 add hl, sp
970 ld a, (hl)
971 inc hl
972 or a, (hl)
973 ; common peephole 66b used hl instead of %4.
974 } if immdInRange(-128 127 '-' %2 1 %5), same(%5 %3), notUsed(%4 'hl')
976 replace restart {
977 ld %4, #%1
978 add %4, sp
979 %5 %2, %3 (%4)
980 } by {
981 ld hl, #%1 + %3
982 add hl, sp
983 %5 %2, (hl)
984 ; common peephole 67a used hl instead of %4.
985 } if same(%5 'bit' 'res' 'set'), notUsed(%4 'hl')
987 replace restart {
988 ld %4, #%1
989 add %4, sp
990 %5 %3, %2 (%4)
991 } by {
992 ld hl, #%1 + %2
993 add hl, sp
994 %5 %3, (hl)
995 ; common peephole 67b used hl instead of %4.
996 } if same(%5 'adc' 'add' 'and' 'ld' 'or' 'sbc' 'sub' 'xor'), notUsed(%4 'hl')
998 replace restart {
999 push hl
1000 ld hl, #%1
1001 add hl, sp
1002 ld a, (hl)
1003 inc hl
1004 ld h, (hl)
1005 ld l, a
1006 } by {
1007 ; common peephole 67c removed load back from stack.
1008 push hl
1009 }if operandsLiteral(%1), immdInRange(0 0 '+' %1 0 %2)
1011 replace restart {
1012 inc hl
1013 ld a, (hl)
1014 dec hl
1015 or a, (hl)
1016 } by {
1017 ld a, (hl)
1018 inc hl
1019 or a, (hl)
1020 ; common peephole 68 reversed ld and or.
1021 } if notUsed('hl')
1023 // can be further optimized to (hl+) on gbz80
1024 replace restart {
1025 ld %1, l
1026 ld %2, h
1027 inc %3
1028 } by {
1029 ; common peephole 69 incremented in hl instead of %3.
1030 inc hl
1031 ld %1, l
1032 ld %2, h
1033 } if canJoinRegs(%2 %1 %4), same(%4 %3), notUsed('hl')
1035 replace restart {
1036 ld %4, #%1
1037 %3 %2 (%4)
1038 } by {
1039 ; common peephole 70 %3 (hl) instead of %2 (%4).
1040 ld hl, #%1 + %2
1041 %3 (hl)
1042 } if same(%3 'inc' 'dec'), notUsed(%4 'hl')
1044 replace restart {
1045 ld %1, %2
1046 push %3
1047 inc sp
1048 } by {
1049 ; common peephole 71 eliminate unnecessary initialization of %1 register.
1050 push %3
1051 inc sp
1052 } if same(%1 'c' 'e' 'l' 'ixl' 'iyl'), canJoinRegs('' %1 %4), same(%3 %4), notUsed(%1)
1054 replace restart {
1055 ld a, %1 (%2)
1056 bit %3, a
1057 } by {
1058 ; common peephole 72 tested bit %3 of %1 (%2) directly instead of going through a.
1059 bit %3, %1 (%2)
1060 } if notUsed('a')
1062 replace restart {
1063 ld %1, (hl)
1064 bit %2, %1
1065 } by {
1066 ; common peephole 73 tested bit %2 of (hl) directly instead of going through %1.
1067 bit %2, (hl)
1068 } if notUsed(%1)
1070 replace restart {
1071 ld a, %1
1072 bit %2, a
1073 } by {
1074 ; common peephole 74 tested bit %2 of %1 directly instead of going through a.
1075 bit %2, %1
1076 } if notUsed('a'), canAssign(%1 'b')
1078 replace restart {
1079 ld a, %1
1080 %3 %2, a
1081 ld %1, a
1082 } by {
1083 ; common peephole 75 %3 bit %2 of %1 directly instead of going through a.
1084 %3 %2, %1
1085 ld a, %1
1086 } if same(%3 'set' 'res'), canAssign(%1 'b'), notSame(%1 '(hl+)' '(hl-)')
1087 // canAssign(%1 'b') is true, iff set b, %1 is possible.
1089 replace restart {
1090 ld a, %1 (%2)
1091 %4 %3, a
1092 ld %1 (%2), a
1093 } by {
1094 ; common peephole 76 %4 bit %3 of %1 (%2) directly instead of going through a.
1095 %4 %3, %1 (%2)
1096 ld a, %1 (%2)
1097 } if same(%4 'set' 'res')
1099 replace restart {
1100 ld %1, #%2 + %3
1101 inc %1
1102 } by {
1103 ld %1, #%2 + %4
1104 ; common peephole 77a incremented immediate.
1105 } if operandsLiteral(%3), immdInRange(0 256 '+' %3 1 %4), notUsed('f')
1107 replace restart {
1108 ld %1, #%2 - %3
1109 inc %1
1110 } by {
1111 ld %1, #%2 - %4
1112 ; common peephole 77b incremented immediate.
1113 } if operandsLiteral(%3), immdInRange(0 256 '-' %3 1 %4), notUsed('f')
1115 replace restart {
1116 ld %1, #%2 + %3
1117 dec %1
1118 } by {
1119 ld %1, #%2 + %4
1120 ; common peephole 77c decremented immediate.
1121 } if operandsLiteral(%3), immdInRange(0 256 '-' %3 1 %4), notUsed('f')
1123 replace restart {
1124 ld %1, #%2 - %3
1125 dec %1
1126 } by {
1127 ld %1, #%2 - %4
1128 ; common peephole 77d decremented immediate.
1129 } if operandsLiteral(%3), immdInRange(0 256 '+' %3 1 %4), notUsed('f')
1131 replace {
1132 ld %1, #%2 - 0
1133 } by {
1134 ld %1, #%2 + 0
1135 ; common peephole 77e changed -0 to +0.
1138 replace {
1139 ld %1, #%2 + 0
1140 dec %1
1141 } by {
1142 ld %1, #%2 - 1
1143 ; common peephole 77f decremented immediate.
1144 } if notUsed('f')
1146 // should improve flag based optimizations
1147 replace restart {
1148 jp %1, %2
1149 jp %2
1150 } by {
1151 ; common peephole 78 removed redundant jp
1152 jp %2
1153 } if labelRefCountChange(%2 -1)
1155 replace restart {
1156 jp NC, %1
1157 jp %2
1159 } by {
1160 jp C, %2
1161 ; common peephole 79 removed jp by using inverse jump logic
1163 } if operandsNotRelated(%2 '(hl)' '(ix)' '(iy)'), labelRefCountChange(%1 -1)
1165 replace restart {
1166 jp C, %1
1167 jp %2
1169 } by {
1170 jp NC, %2
1171 ; common peephole 80 removed jp by using inverse jump logic
1173 } if operandsNotRelated(%2 '(hl)' '(ix)' '(iy)'), labelRefCountChange(%1 -1)
1175 replace restart {
1176 jp NZ, %1
1177 jp %2
1179 } by {
1180 jp Z, %2
1181 ; common peephole 81 removed jp by using inverse jump logic
1183 } if operandsNotRelated(%2 '(hl)' '(ix)' '(iy)'), labelRefCountChange(%1 -1)
1185 replace restart {
1186 jp Z, %1
1187 jp %2
1189 } by {
1190 jp NZ, %2
1191 ; common peephole 82 removed jp by using inverse jump logic
1193 } if operandsNotRelated(%2 '(hl)' '(ix)' '(iy)'), labelRefCountChange(%1 -1)
1195 replace restart {
1196 jp %5
1197 } by {
1198 jp %6
1199 ; common peephole 83 jumped to %6 directly instead of via %5.
1200 } if labelIsUncondJump(), notSame(%5 %6), labelRefCountChange(%5 -1), labelRefCountChange(%6 +1)
1202 replace restart {
1203 jp %1, %5
1204 } by {
1205 jp %1, %6
1206 ; common peephole 84 jumped to %6 directly instead of via %5.
1207 } if labelIsUncondJump(), notSame(%5 %6), labelRefCountChange(%5 -1), labelRefCountChange(%6 +1)
1209 replace restart {
1210 jp %1
1212 } by {
1213 ; common peephole 85a eliminated jump.
1215 } if labelRefCountChange(%1 -1)
1217 replace restart {
1218 jp %1
1221 } by {
1222 ; common peephole 85b eliminated jump.
1225 } if labelRefCountChange(%1 -1)
1227 // A peephole that makes the code longer. Let's hope it's worth it in speed gain and further optimization potential.
1228 replace restart {
1229 ld a, #0x00
1231 bit %2, a
1232 jp Z, %3
1233 } by {
1234 ld a, #0x00
1235 jp %3
1236 ; common peephole 86 jumped directly to %3 instead of testing a first.
1238 bit %2, a
1239 jp Z, %3
1240 } if labelRefCountChange(%3 +1)
1242 replace restart {
1243 ld %1, %2
1244 jp %3
1245 jp %4
1246 } by {
1247 ld %1, %2
1248 jp %3
1249 ; common peephole 87a removed unreachable jump to %4
1250 } if labelRefCountChange(%4 -1)
1252 replace restart {
1253 jp %1
1255 jp %3
1256 } by {
1257 ; common peephole 87b removed unreachable jump to %3
1258 jp %1
1259 } if labelRefCount(%2 0), labelRefCountChange(%3 -1)
1261 replace restart {
1262 ld %1, #0x01
1263 bit 0, %1
1264 jp Z, %2
1265 } by {
1266 ld %1, #0x01
1267 ; common peephole 89 removed impossible jump to %2.
1268 } if labelRefCountChange(%2 -1)
1270 replace restart {
1271 rlca
1272 and a, #0x01
1273 jp Z, %1
1274 } by {
1275 rlca
1276 ; common peephole 90a removed and by changing jump condition.
1277 jp NC, %1
1278 } if notUsed('a'), notUsedFrom(%1 'a')
1280 replace restart {
1281 rlca
1282 and a, #0x01
1283 jp NZ, %1
1284 } by {
1285 ; common peephole 90b removed and by changing jump condition.
1286 rlca
1287 jp C, %1
1288 } if notUsed('a'), notUsedFrom(%1 'a')
1290 replace {
1291 ld %5, #%1
1292 ld %6, #%2
1293 } by {
1294 ; common peephole 92a combined constant loads into register pair.
1295 ld %7, #%4
1296 } if canJoinRegs(%6 %5 %7), operandsLiteral(%1 %2), immdInRange(0x00 0xffff '*' %2 0x100 %3), immdInRange(0x00 0xffff '|' %3 %1 %x4)
1298 replace {
1299 xor a, a
1300 ld %5, a
1301 ld %6, #%2
1302 } by {
1303 ; common peephole 92b combined constant loads into register pair.
1304 ld %7, #%4
1305 } if canJoinRegs(%6 %5 %7), operandsLiteral(%2), immdInRange(0x00 0xffff '*' %2 0x100 %x4), notUsed('a' 'cf' 'zf')
1307 replace {
1308 xor a, a
1309 ld %5, #%1
1310 ld %6, a
1311 } by {
1312 ; common peephole 92c combined constant loads into register pair.
1313 ld %7, #%1
1314 } if canJoinRegs(%6 %5 %7), operandsLiteral(%1), notUsed('a' 'cf' 'zf')
1316 replace {
1317 ld %5, #%1
1318 ld %6, #%2
1319 } by {
1320 ; common peephole 93a combined constant loads into register pair.
1321 ld %7, #%4
1322 } if canJoinRegs(%5 %6 %7), operandsLiteral(%1 %2), immdInRange(0x00 0xffff '*' %1 0x100 %3), immdInRange(0x00 0xffff '|' %3 %2 %x4)
1324 replace {
1325 xor a, a
1326 ld %5, a
1327 ld %6, #%2
1328 } by {
1329 ; common peephole 93b combined constant loads into register pair.
1330 ld %7, #%2
1331 } if canJoinRegs(%5 %6 %7), operandsLiteral(%2), notUsed('a' 'cf' 'zf')
1333 replace {
1334 xor a, a
1335 ld %5, #%1
1336 ld %6, a
1337 } by {
1338 ; common peephole 93c combined constant loads into register pair.
1339 ld %7, #%4
1340 } if canJoinRegs(%5 %6 %7), operandsLiteral(%1), immdInRange(0x00 0xffff '*' %1 0x100 %x4), notUsed('a' 'cf' 'zf')
1342 replace {
1343 ld %8, #%1
1344 ld %5, %8
1345 ld %6, #%2
1346 } by {
1347 ld %8, #%1
1348 ld %7, #%4
1349 ; common peephole 93d combined constant loads into register pair.
1350 } if canJoinRegs(%5 %6 %7), operandsLiteral(%1 %2), immdInRange(0x00 0xffff '*' %1 0x100 %3), immdInRange(0x00 0xffff '|' %3 %2 %x4)
1352 replace {
1353 ld %1, #%2
1354 xor a, a
1355 } by {
1356 ; common peephole 94a reused constant #0 loaded into register.
1357 xor a, a
1358 ld %1, a
1359 } if same(%1 'a' 'b' 'c' 'd' 'e' 'h' 'l'), operandsLiteral(%2), immdInRange(0 0 '+' %2 0 %3)
1361 replace restart {
1362 xor a, a
1363 ld (%1), a
1364 xor a, a
1365 } by {
1366 xor a, a
1367 ld (%1), a
1368 ; common peephole 94a' reused constant #0 in a.
1371 replace {
1372 xor a, a
1373 ld (%1), a
1374 ld (hl), #%2
1375 } by {
1376 ; common peephole 94b reused constant #0 loaded into register.
1377 xor a, a
1378 ld (%1), a
1379 ld (hl), a
1380 } if same(%1 'hl' 'hl+' 'hl-'), operandsLiteral(%2), immdInRange(0 0 '+' %2 0 %3)
1382 replace {
1383 xor a, a
1384 ld (hl), a
1385 %1 hl
1386 ld (hl), #%2
1387 } by {
1388 ; common peephole 94c reused constant #0 loaded into register.
1389 xor a, a
1390 ld (hl), a
1391 %1 hl
1392 ld (hl), a
1393 } if same(%1 'inc' 'dec'), operandsLiteral(%2), immdInRange(0 0 '+' %2 0 %3)
1395 replace {
1396 ld %1, %2
1397 push %1
1398 ld %1, %2
1399 } by {
1400 ld %1, %2
1401 push %1
1402 ; common peephole 94d pushed register pair twice.
1405 replace {
1406 ld %1, #%2
1407 ld %3, #%4
1408 push %1
1409 push %3
1410 } by {
1411 ld %1, #%2
1412 ld %3, #%4
1413 push %1
1414 push %1
1415 ; common peephole 94e pushed register pair twice.
1416 }if operandsLiteral(%2), operandsLiteral(%4), immdInRange(0 0 '-' %2 %4 %5)
1418 replace {
1419 ld %1, #%2
1420 ld %3, #%4
1421 push %3
1422 push %1
1423 } by {
1424 ld %1, #%2
1425 ld %3, #%4
1426 push %1
1427 push %1
1428 ; common peephole 94f pushed register pair twice.
1429 }if operandsLiteral(%2), operandsLiteral(%4), immdInRange(0 0 '-' %2 %4 %5)
1431 // optimizes genRet
1432 replace restart {
1433 ld (%1), %2
1434 inc %1
1435 ld (%1), %3
1436 dec %1
1437 ld %4, (%1)
1438 inc %1
1439 ld %5, (%1)
1440 } by {
1441 ; common peephole 95a switched loads to %4 and %5.
1442 ld (%1), %2
1443 inc %1
1444 ld (%1), %3
1445 ld %5, (%1)
1446 dec %1
1447 ld %4, (%1)
1448 inc %1
1449 } if operandsNotRelated(%4 %5 %1), operandsNotRelated(%5 %1)
1451 replace restart {
1452 ld (%1), %2
1453 dec %1
1454 ld %4, (%1)
1455 inc %1
1456 ld %5, (%1)
1457 } by {
1458 ; common peephole 95b switched loads to %4 and %5.
1459 ld (%1), %2
1460 ld %5, (%1)
1461 dec %1
1462 ld %4, (%1)
1463 inc %1
1464 } if operandsNotRelated(%4 %5 %1), operandsNotRelated(%5 %1)
1466 // improves genRet after (hl) access
1467 replace restart {
1468 %2 (%1)
1469 dec %1
1470 ld %4, (%1)
1471 inc %1
1472 ld %5, (%1)
1473 } by {
1474 ; common peephole 95c switched loads to %4 and %5.
1475 %2 (%1)
1476 ld %5, (%1)
1477 dec %1
1478 ld %4, (%1)
1479 inc %1
1480 }if operandsNotRelated(%4 %5 %1), operandsNotRelated(%5 %1)
1482 replace restart {
1484 %2 %3
1485 } by {
1486 ; common peephole 96a move %2 %3 before %1
1487 %2 %3
1489 } if same(%2 'inc' 'dec'), same(%3 'hl'), same(%1 'rlca' 'rrca' 'rra' 'rla' 'cpl' 'scf' 'daa' 'ccf' 'sra' 'swap' 'nop')
1491 replace restart {
1492 %4 %1, %2
1493 %3 %5
1494 } by {
1495 ; common peephole 96b move %3 %5 before %4 %1, %2
1496 %3 %5
1497 %4 %1, %2
1498 } if same(%3 'inc' 'dec'), same(%5 'hl'), same(%4 'ld' 'ldh' 'cp' 'add' 'adc' 'and' 'or' 'xor' 'sub' 'sbc' 'set' 'res' 'bit' 'in' 'out' 'in0' 'out0'), operandsNotRelated(%1 %5), operandsNotRelated(%2 %5)
1500 replace restart {
1501 %2 %1
1502 %3 %4
1503 } by {
1504 ; common peephole 96c move %3 %4 before %2 %1
1505 %3 %4
1506 %2 %1
1507 } if same(%3 'inc' 'dec'), same(%4 'hl'), same(%2 'inc' 'dec' 'rl' 'rlc' 'rr' 'rrc' 'srl' 'sla' 'sra' 'swap'), operandsNotRelated(%1 %4), operandsNotRelated(%2 %4)
1509 replace restart {
1510 %2 %1
1511 %3 %4
1512 } by {
1513 ; common peephole 96d move %3 %4 before %2 %1
1514 %3 %4
1515 %2 %1
1516 } if same(%3 'inc' 'dec'), same(%4 'hl'), same(%2 'push' 'pop'), notSame(%1 %4)
1518 // check if constant loaded into (hl) is the same that's loaded into the second register
1519 replace {
1520 ld (hl), #%2
1521 ld %1, #%3
1522 } by {
1523 ; common peephole 97a reused constant loaded into register pair. %2 %3
1524 ld %1, #%3
1525 ld (hl), %5
1526 } if same(%1 'bc' 'de'), operandsLiteral(%2 %3), canSplitReg(%1 %4 %5), immdInRange(0x00 0xff '&' %3 0xff %7), immdInRange(0 0 '-' %7 %2 %8)
1527 // ., ., ., ., get second byte, compare second byte with %2
1529 // check if constant loaded into (hl) is the same that's loaded into the first register
1530 replace {
1531 ld (hl), #%2
1532 ld %1, #%3
1533 } by {
1534 ; common peephole 97b reused constant loaded into register pair.
1535 ld %1, #%3
1536 ld (hl), %4
1537 } if same(%1 'bc' 'de'), operandsLiteral(%2 %3), canSplitReg(%1 %4 %5), immdInRange(0x00 0xff '/' %3 0xff %6), immdInRange(0x00 0xff '&' %6 0xff %7), immdInRange(0 0 '-' %7 %2 %8)
1538 // ., ., ., ., bit shift, get second byte, compare second byte with %2
1540 replace restart {
1541 ld %1, a
1542 ld a, %1
1543 } by {
1544 ld %1, a
1545 ; common peephole 98 removed redundant load from %1 into a.
1546 } if notVolatile(%1), notSame(%1 '(hl+)' '(hl-)')
1547 // This gives many false negatives and without the test no problems are encountered in the regression tests
1548 // Maybe we can try this after 2.7.0 release
1550 replace restart {
1551 ld %2 (ix), %1
1552 ld %1, %2 (ix)
1553 } by {
1554 ld %2 (ix), %1
1555 ; common peephole 98a removed redundant load of %1 from %2 (ix)
1558 replace restart {
1559 ld %1, a
1560 ld a, %2
1561 or a, %1
1562 } by {
1563 ld %1, a
1564 or a, %2
1565 ; common peephole 99 removed load by reordering or arguments.
1566 } if notVolatile(%1), canAssign('b' %2), notSame(%1 '(hl+)' '(hl-)')
1567 // canAssign('b' %2) is true, iff or a,%2 is possible.
1569 replace restart {
1570 ld %1, (hl)
1571 inc hl
1572 ld a, (hl)
1573 or a, %1
1574 } by {
1575 ld a, (hl)
1576 inc hl
1577 ; common peephole 99a removed load by reordering or arguments.
1578 or a, (hl)
1579 } if notUsed(%1)
1581 replace restart {
1582 or a, #0x00
1583 } by {
1584 or a, a
1585 ; common peephole 99b removed redundant or argument.
1588 replace restart {
1589 and a, %1
1590 or a, a
1591 } by {
1592 and a, %1
1593 ; common peephole 100 removed redundant or after and.
1596 replace restart {
1597 and a, %1 (%2)
1598 or a, a
1599 } by {
1600 and a, %1 (%2)
1601 ; common peephole 100a removed redundant or after and.
1604 replace restart {
1605 %2 %1
1606 ld a, %1
1607 or a, a
1608 } by {
1609 %2 %1
1610 ld a, %1
1611 ; common peephole 100b removed redundant or after %2
1613 } if same(%2 'inc' 'dec'), notUsed('cf' 'hf' 'nf' 'sf' 'pf')
1615 replace restart {
1616 xor a,%1
1617 or a,a
1618 } by {
1619 xor a,%1
1620 ; common peephole 101 removed redundant or after xor.
1623 replace restart {
1624 xor a,%1 (%2)
1625 or a,a
1626 } by {
1627 xor a,%1 (%2)
1628 ; common peephole 102 removed redundant or after xor.
1631 replace restart {
1632 dec a
1633 or a, a
1634 } by {
1635 ; common peephole 102a removed redundant or after dec.
1636 dec a
1637 } if notUsed('cf')
1639 replace restart {
1640 dec %1
1641 ld a, %1
1642 or a, a
1643 } by {
1644 ; common peephole 102b removed redundant or after dec.
1645 dec %1
1646 ld a, %1
1647 } if notUsed('cf')
1649 //TODO: check on other flags
1650 replace restart {
1651 sbc hl, %1
1652 ld a, h
1653 or a, l
1654 jp %2, %3
1655 } by {
1656 sbc hl, %1
1657 jp %2, %3
1658 ; common peephole 102c removed redundant or after sbc.
1659 } if same(%2 'NZ' 'Z')
1661 replace restart {
1662 sub a, %1
1663 ld %2, a
1664 or a, a
1665 jp %3, %4
1666 } by {
1667 sub a, %1
1668 ld %2, a
1669 ; common peephole 102d removed redundant or after sub.
1670 jp %3, %4
1671 } if same(%3 'NZ' 'Z')
1673 replace {
1674 ld %1,%2
1675 ld a,%2
1676 } by {
1677 ld a,%2
1678 ld %1,a
1679 ; common peephole 103 loaded value in a first and used it next
1680 } if notVolatile(%1 %2), canAssign(%1 'a'), operandsNotRelated(%1 %2), notSame(%1 '(hl+)' '(hl-)'), notSame(%2 '(hl+)' '(hl-)')
1682 // Cannot allow (hl) for %2, as otherwise the first ld could have a different width from the second (8- vs 16-bit). E.g. ld hl, (hl)
1683 replace restart {
1684 ld %2, #%1
1685 ld %3, #%1
1686 } by {
1687 ; common peephole 103b loaded constant in %2 first and used it next
1688 ld %2, #%1
1689 ld %3, %2
1690 } if notVolatile(%2), canAssign(%3 %2), same(%2 'a' 'b' 'c' 'd' 'e' 'h' 'l')
1692 replace restart {
1693 ld %1,%2
1694 ld %3,%4
1695 ld %2,%1
1696 ld %4,%3
1697 } by {
1698 ld %1,%2
1699 ld %3,%4
1700 ; common peephole 104 removed redundant load from %3%1 into %4%2
1701 } if notVolatile(%1 %2 %3 %4), notSame(%1 '(hl+)' '(hl-)'), notSame(%2 '(hl+)' '(hl-)'), notSame(%3 '(hl+)' '(hl-)'), notSame(%4 '(hl+)' '(hl-)')
1703 replace restart {
1704 ld %2, %1
1705 %3 %2
1706 ld %1, %2
1707 } by {
1708 %3 %1
1709 ld %2, %1
1710 ; common peephole 104b %3 %1 directly to remove redundant load from %2 into %1
1711 } if same(%1 'a' 'b' 'c' 'd' 'e' 'h' 'l' '(hl)'), same(%3 'inc' 'dec')
1713 replace restart {
1714 push de
1715 inc sp
1716 ld a,e
1717 push af
1718 inc sp
1719 } by {
1720 push de
1721 ; common peephole 105 pushed de
1722 } if notUsed('a')
1724 replace restart {
1725 ld iy,%1
1726 add iy,sp
1727 ld sp,iy
1728 } by {
1729 ld hl,%1
1730 add hl,sp
1731 ld sp,hl
1732 ; common peephole 106 fixed stack using hl instead of iy.
1733 } if notUsed('hl'), notUsed('iy')
1735 replace restart {
1736 ld a,%1
1737 sub a,%2
1738 jp %3,%4
1739 ld a,%1
1740 } by {
1741 ld a,%1
1742 cp a,%2
1743 jp %3,%4
1744 ; common peephole 107 removed load from %1 into a by replacing sub with cp
1745 assert a=%1
1746 } if notVolatile(%1), notUsedFrom(%4 'a'), notSame(%1 '(hl+)' '(hl-)')
1748 replace restart {
1749 assert a=%1
1750 sub a,%2
1751 jp %3,%4
1752 ld a,%1
1753 } by {
1754 cp a,%2
1755 jp %3,%4
1756 ; common peephole 108 removed load from %1 into a by replacing sub with cp
1757 assert a=%1
1758 } if notUsedFrom(%4 'a')
1760 replace restart {
1761 assert a=%1
1762 } by {
1765 replace restart {
1766 rlca
1767 ld a,#0x00
1769 } by {
1770 rlca
1771 and a,#0x01
1772 ; common peephole 109 replaced zero load, rla by and since rlca writes the same value to carry bit and least significant bit.
1775 replace restart {
1776 ld %1,%2
1777 push %1
1778 pop %4
1779 ld %1,%3
1780 } by {
1781 ld %4,%2
1782 ; common peephole 110 moved %2 directly into de instead of going through %1.
1783 ld %1,%3
1786 replace restart {
1787 add a,#0x00
1788 ld %2,a
1789 ld a,%3
1790 adc a,%4
1791 } by {
1792 ; common peephole 111 removed lower part of multibyte addition.
1793 ld %2,a
1794 ld a,%3
1795 add a,%4
1798 replace restart {
1799 ld a, l
1800 add a, #%1
1801 ld e, a
1802 ld a, h
1803 adc a, #%2
1804 ld d, a
1805 } by {
1806 ld de, #%4
1807 add hl, de
1808 ; common peephole 112 used 16-bit addition.
1809 ld e, l
1810 ld d, h
1811 ld a, h
1812 } if operandsLiteral(%1 %2), immdInRange(0x00 0xffff '*' %2 0x100 %3), immdInRange(0x00 0xffff '|' %3 %1 %x4), notUsed('hl')
1814 replace restart {
1815 ld a, l
1816 add a, #%1
1817 ld c, a
1818 ld a, h
1819 adc a, #%2
1820 ld b, a
1821 } by {
1822 ld bc, #%4
1823 add hl,bc
1824 ; common peephole 113 used 16-bit addition.
1825 ld c, l
1826 ld b, h
1827 ld a, h
1828 } if operandsLiteral(%1 %2), immdInRange(0x00 0xffff '*' %2 0x100 %3), immdInRange(0x00 0xffff '|' %3 %1 %x4), notUsed('hl')
1830 replace restart {
1831 ld l,%1 (ix)
1832 ld h,%2 (ix)
1833 ld a,(hl)
1834 inc a
1835 ld l,%1 (ix)
1836 ld h,%2 (ix)
1837 ld (hl),a
1838 } by {
1839 ld l,%1 (ix)
1840 ld h,%2 (ix)
1841 inc (hl)
1842 ; common peephole 114 incremented in (hl) instead of going through a.
1843 } if notUsed('a')
1845 replace restart {
1846 ld %1, (hl)
1847 inc %1
1848 ld (hl), %1
1849 } by {
1850 inc (hl)
1851 ; common peephole 115 incremented in (hl) instead of going through %1.
1852 } if notUsed(%1)
1854 replace restart {
1855 ld %1, (hl)
1856 ld a, %2
1857 %3 a, %1
1858 } by {
1859 ld a, %2
1860 ; common peephole 115a used (hl) in in %3 instead of going through %1.
1861 %3 a, (hl)
1862 } if notVolatile(%2), notUsed(%1), same(%3 'adc' 'and' 'add' 'cp' 'or' 'sbc' 'sub' 'xor')
1864 replace restart {
1865 ld %1, (hl)
1866 xor a, a
1867 %3 a, %1
1868 } by {
1869 xor a, a
1870 ; common peephole 115b used (hl) in subtraction instead of going through %1.
1871 %3 a, (hl)
1872 } if notUsed(%1), same(%3 'and' 'add' 'cp' 'or' 'sub' 'xor')
1874 // TODO: Check for volatile?
1875 replace restart {
1876 ld %1, %2 (%3)
1877 inc %1
1878 ld %2 (%3), %1
1879 } by {
1880 inc %2 (%3)
1881 ld %1, %2 (%3)
1882 ; common peephole 116 incremented in %2 (%3) instead of going through %1.
1883 } if canAssign('a' %1)
1885 // TODO: Check for volatile?
1886 replace restart {
1887 ld %1, %2 (%3)
1888 dec %1
1889 ld %2 (%3), %1
1890 } by {
1891 dec %2 (%3)
1892 ld %1, %2 (%3)
1893 ; common peephole 117 decremented in %2 (%3) instead of going through %1.
1894 } if canAssign('a' %1)
1896 replace restart {
1897 ld %1,a
1898 ld a,%2
1899 add a,%1
1900 } by {
1901 ld %1, a
1902 ; common peephole 118 removed load by exploiting commutativity of addition.
1903 add a,%2
1904 } if notSame(%2 '(bc)' '(de)'), canAssign('b' %2)
1905 // canAssign('b' %2) is true, iff add a,%2 is possible.
1907 replace restart {
1908 ld c, l
1909 ld b, h
1910 ld hl, #%1
1911 add hl, bc
1912 } by {
1913 ; common peephole 119 removed loads by exploiting commutativity of addition.
1914 ld bc, #%1
1915 add hl, bc
1916 } if notUsed('bc')
1918 replace restart {
1919 ld hl, #%1
1920 add hl, %2
1921 ld bc, #%4
1922 add hl, bc
1923 } by {
1924 ; common peephole 120 removed loads by exploiting commutativity of addition.
1925 ld hl, #%1 + %4
1926 add hl, %2
1927 } if notUsed('bc')
1929 replace restart {
1930 or a, %1
1931 jp NZ, %2
1932 ld %3, #0x00
1933 } by {
1934 or a, %1
1935 jp NZ, %2
1936 ld %3, a
1937 ; common peephole 121a replaced constant #0x00 by a (which has just been tested to be #0x00).
1940 replace restart {
1941 and a, %1
1942 jp NZ, %2
1943 ld %3, #0x00
1944 } by {
1945 and a, %1
1946 jp NZ, %2
1947 ld %3, a
1948 ; common peephole 121b replaced constant #0x00 by a (which has just been tested to be #0x00).
1951 replace restart {
1952 ld a, #%1
1953 } by {
1954 ; common peephole 123 optimize ld a, %1
1955 xor a, a
1956 } if operandsLiteral(%1), immdInRange(0 0 '+' %1 0 %2), notUsed('f')
1958 replace restart {
1959 sub a, %1
1960 jp NZ, %2
1961 ld %3, #0x00
1962 } by {
1963 sub a, %1
1964 jp NZ, %2
1965 ld %3, a
1966 ; common peephole 124 replaced constant #0x00 by a (which has just been tested to be #0x00).
1969 replace restart {
1970 inc a
1971 jp NZ, %1
1972 ld %2, #0x00
1973 } by {
1974 inc a
1975 jp NZ, %1
1976 ld %2, a
1977 ; common peephole 125a replaced constant #0x00 by a (which has just been tested to be #0x00).
1980 replace restart {
1981 dec a
1982 jp NZ, %1
1983 ld %2, #0x00
1984 } by {
1985 dec a
1986 jp NZ, %1
1987 ld %2, a
1988 ; common peephole 125b replaced constant #0x00 by a (which has just been tested to be #0x00).
1991 replace restart {
1992 or a, %1
1993 jp NZ, %2
1994 ld a, %3
1995 or a, a
1996 } by {
1997 or a, %1
1998 jp NZ, %2
1999 or a, %3
2000 ; common peephole 126a shortened or using a (which has just been tested to be #0x00).
2001 } if canAssign('b' %3)
2002 // canAssign('b' %2) is true, iff or a,%2 is possible.
2004 replace restart {
2005 or a, %1
2006 ld %4, a
2007 jp NZ, %2
2008 ld a, %3
2009 or a, a
2010 } by {
2011 or a, %1
2012 ld %4, a
2013 jp NZ, %2
2014 or a, %3
2015 ; common peephole 126b shortened or using a (which has just been tested to be #0x00).
2016 } if canAssign('b' %3)
2018 replace restart {
2019 sub a, %1
2020 jp NZ, %2
2021 ld a, %3
2022 or a, a
2023 } by {
2024 sub a, %1
2025 jp NZ, %2
2026 or a, %3
2027 ; common peephole 127a shortened or using a (which has just been tested to be #0x00).
2028 } if canAssign('b' %3)
2029 // canAssign('b' %2) is true, iff or a,%2 is possible.
2031 replace restart {
2032 sub a, %1
2033 ld %4, a
2034 jp NZ, %2
2035 ld a, %3
2036 or a, a
2037 } by {
2038 sub a, %1
2039 ld %4, a
2040 jp NZ, %2
2041 or a, %3
2042 ; common peephole 127b shortened or using a (which has just been tested to be #0x00).
2043 } if canAssign('b' %3)
2045 //TODO: check on other flags
2046 replace restart {
2048 ld a, (%1)
2049 %4 a, a
2050 jp Z, %2
2051 inc %1
2052 jp %3
2054 } by {
2056 ld a, (%1)
2057 inc %1
2058 %4 a, a
2059 jp NZ, %3
2060 ; common peephole 128a sped up loop body.
2061 dec %1
2063 } if same(%4 'or' 'and'), canSplitReg(%1 %0 %0), labelRefCountChange(%2 -1)
2065 //TODO: check on other flags
2066 replace restart {
2068 ld a, (%5)
2069 inc %5
2070 ld %3, a
2071 ld a, (%6)
2072 inc %6
2073 sub a, %3
2074 ld %4, a
2075 jp NZ, %2
2076 or a,%3
2077 jp NZ, %1
2079 } by {
2081 ld a, (%5)
2082 inc %5
2083 ld %3, a
2084 ld a, (%6)
2085 inc %6
2086 sub a, %3
2087 jp NZ, %2
2088 cp a,%3
2089 jp NZ, %1
2091 ; common peephole 128b sped up loop body.
2092 ld %4, a
2093 } if canSplitReg(%5 %7 %8), canSplitReg(%6 %9 %10), operandsNotRelated(%3 %5 %6), operandsNotRelated(%3 %5 %6), notSame(%3 %4), labelRefCount(%2 1)
2095 replace restart {
2097 ld a, (%5)
2098 ld %3, a
2099 inc %5
2100 ld a, (%6)
2101 inc %6
2102 sub a, %3
2103 ld %4, a
2104 jp NZ, %2
2105 or a,%3
2106 jp NZ, %1
2108 } by {
2110 ld a, (%5)
2111 inc %5
2112 ld %3, a
2113 ld a, (%6)
2114 inc %6
2115 sub a, %3
2116 jp NZ, %2
2117 cp a,%3
2118 jp NZ, %1
2120 ; common peephole 128c sped up loop body.
2121 ld %4, a
2122 } if canSplitReg(%5 %7 %8), canSplitReg(%6 %9 %10), operandsNotRelated(%3 %5 %6), operandsNotRelated(%3 %5 %6), notSame(%3 %4), labelRefCount(%2 1)
2124 replace restart {
2125 ld hl,#%1
2126 add hl,%2
2127 inc hl
2128 } by {
2129 ld hl,#%3
2130 add hl,%2
2131 ; common peephole 129a moved increment of hl to constant.
2132 } if operandsLiteral(%1), immdInRange(0 0xFFFF '+' %1 1 %x3)
2134 // breaks 130 otherwise
2135 replace restart {
2136 ld hl,#%1
2137 add hl,%2
2138 dec hl
2139 } by {
2140 ld hl,#%3
2141 add hl,%2
2142 ; common peephole 129b moved decrement of hl to constant.
2143 } if operandsLiteral(%1), immdInRange(0 0xFFFF '-' %1 1 %x3)
2145 replace restart {
2146 ld hl,#%1
2147 add hl,%2
2148 inc hl
2149 } by {
2150 ld hl,#%1 + 1
2151 add hl,%2
2152 ; common peephole 129c moved increment of hl to constant.
2155 replace restart {
2156 ld hl,#%1
2157 add hl,%2
2158 dec hl
2159 } by {
2160 ld hl,#%1 - 1
2161 add hl,%2
2162 ; common peephole 129d moved decrement of hl to constant.
2165 replace {
2166 ld %1, #%2 + 0
2167 } by {
2168 ; common peephole 130a removed unnecessary +0 from constant
2169 ld %1, #%2
2172 //TODO: %2 matches 4+1+1
2173 replace {
2174 ld %1, #%2 + %3
2175 } by {
2176 ; common peephole 130b added +%3 to immediate %2
2177 ld %1, #%4
2178 } if operandsLiteral(%2 %3), immdInRange(0 0xFF '+' %2 %3 %x4)
2180 replace {
2181 ld %1, #%2 + %3
2182 } by {
2183 ; common peephole 130c added +%3 to immediate %2
2184 ld %1, #%4
2185 } if operandsLiteral(%2 %3), immdInRange(0 0xFFFF '+' %2 %3 %x4), canSplitReg(%1 %0 %0)
2187 replace {
2188 ld %1, #%2 - 0
2189 } by {
2190 ; common peephole 130d removed unnecessary -0 from constant
2191 ld %1, #%2
2194 replace {
2195 ld %1, #%2 - %3
2196 } by {
2197 ; common peephole 130e subtracted -%3 from immediate %2
2198 ld %1, #%4
2199 } if operandsLiteral(%2 %3), immdInRange(0 0xFF '-' %2 %3 %x4)
2201 replace {
2202 ld %1, #%2 - %3
2203 } by {
2204 ; common peephole 130f subtracted -%3 from to immediate %2
2205 ld %1, #%4
2206 } if operandsLiteral(%2 %3), immdInRange(0 0xFFFF '-' %2 %3 %x4), canSplitReg(%1 %0 %0)
2209 // Bug #3102
2210 //replace {
2211 // ld %1, (#%2 + 0)
2212 //} by {
2213 // ; common peephole 130g removed unnecessary +0 to immediate
2214 // ld %1, (#%2)
2217 replace {
2218 ld (#%2 + 0), %1
2219 } by {
2220 ; common peephole 130h removed unnecessary +0 to immediate
2221 ld (#%2), %1
2224 replace restart {
2225 push hl
2226 pop iy
2227 pop hl
2228 inc iy
2229 } by {
2230 inc hl
2231 push hl
2232 pop iy
2233 pop hl
2234 ; common peephole 131a incremented in hl instead of iy.
2237 replace restart {
2238 push bc
2239 pop iy
2240 inc iy
2241 } by {
2242 inc bc
2243 push bc
2244 pop iy
2245 ; common peephole 131b incremented in bc instead of iy.
2246 } if notUsed('bc')
2248 replace restart {
2249 ld hl,%1
2250 add hl,%2
2251 push hl
2252 pop iy
2253 } by {
2254 ld iy,%1
2255 add iy,%2
2256 ; common peephole 132 added in iy instead of hl.
2257 } if notUsed('hl'), notSame(%2 'hl')
2259 replace restart {
2260 pop af
2261 ld sp,%1
2262 } by {
2263 ; common peephole 133 removed redundant pop af.
2264 ld sp,%1
2265 } if notUsed('a')
2267 replace restart {
2268 inc sp
2269 ld sp,%1
2270 } by {
2271 ; common peephole 134 removed redundant inc sp.
2272 ld sp,%1
2275 replace restart {
2276 call %1
2278 } by {
2279 jp %1
2280 ; common peephole 135 replaced call at end of function by jump (tail call optimization).
2281 } if symmParmStack(%1)
2283 // Callee saves ix.
2284 replace restart {
2285 call %1
2286 pop ix
2288 } by {
2289 pop ix
2290 jp %1
2291 ; common peephole 136 replaced call at end of function by jump moving call beyond pop ix (tail call optimization).
2292 } if symmParmStack(%1)
2294 replace restart {
2295 ld %1,#%2
2296 ld %3,%4
2297 ld %1,#%2
2298 } by {
2299 ld %1,#%2
2300 ld %3,%4
2301 ; common peephole 137 removed load of #%2 into %1 since it's still there.
2302 } if notVolatile(%1), operandsNotRelated(%3 %1), notSame(%1 '(hl+)' '(hl-)')
2304 replace restart {
2305 ld hl,#%1
2306 ld de,#%1
2307 } by {
2308 ; common peephole 138 used #%1 from hl for load into de.
2309 ld hl,#%1
2310 ld e,l
2311 ld d,h
2314 replace restart {
2315 ld sp,hl
2316 ld hl,#0x0002
2317 add hl,sp
2318 } by {
2319 ld sp, hl
2320 inc hl
2321 inc hl
2322 ; common peephole 139 replaced addition by increment.
2325 replace restart {
2326 ex de, hl
2327 ld hl, #%1
2328 add hl, de
2329 } by {
2330 ; common peephole 140 removed ex exploiting commutativity of addition.
2331 ld de, #%1
2332 add hl, de
2333 } if notUsed('de')
2335 replace restart {
2336 ex de, hl
2337 pop de
2338 add hl, de
2339 } by {
2340 ; common peephole 140a removed ex exploiting commutativity of addition.
2341 pop hl
2342 add hl, de
2343 } if notUsed('de')
2345 replace restart {
2346 ex de, hl
2347 pop hl
2348 add hl, de
2349 } by {
2350 ; common peephole 140b removed ex exploiting commutativity of addition.
2351 pop de
2352 add hl, de
2353 } if notUsed('de')
2355 replace restart {
2356 ex de, hl
2357 push hl
2358 } by {
2359 ; common peephole 140c removed ex before push
2360 push de
2361 } if notUsed('de' 'hl')
2363 replace restart {
2364 ex de, hl
2365 push de
2366 } by {
2367 ; common peephole 140d removed ex before push
2368 push hl
2369 } if notUsed('de' 'hl')
2371 replace restart {
2372 ld hl, #%1
2373 add hl, %2
2374 ex de, hl
2375 inc de
2376 } by {
2377 ld hl, #%1+1
2378 ; common peephole 141 moved increment to constant.
2379 add hl, %2
2380 ex de, hl
2381 } if notUsed('hl')
2384 // those might work for tlcs90 too
2385 replace restart {
2386 pop af
2387 push hl
2388 } by {
2389 ; common peephole 142 used ex to move hl onto the stack.
2390 ex (sp),hl
2391 } if isPort('z80' 'ez80_z80' 'z180' 'z80n'), notUsed('a'), notUsed('hl')
2393 replace restart {
2394 pop af
2395 ld hl, #%1
2396 push hl
2397 } by {
2398 ld hl, #%1
2399 ; common peephole 143 used ex to move hl onto the stack.
2400 ex (sp),hl
2401 } if isPort('z80' 'ez80_z80' 'z180' 'z80n'), notUsed('a'), notUsed('hl')
2403 replace restart {
2404 pop af
2405 inc sp
2406 ld hl,#%1
2407 push hl
2408 } by {
2409 inc sp
2410 ld hl,#%1
2411 ; common peephole 144 used ex to move #%1 onto the stack.
2412 ex (sp),hl
2413 } if isPort('z80' 'ez80_z80' 'z180' 'z80n'), notUsed('a'), notUsed('hl')
2415 replace restart {
2416 pop af
2417 inc sp
2418 ld h, %1 (ix)
2419 ld l, %2 (ix)
2420 push hl
2421 } by {
2422 inc sp
2423 ld h, %1 (ix)
2424 ld l, %2 (ix)
2425 ; common peephole 145 used ex to move %1 (ix) %2 (ix) onto the stack.
2426 ex (sp),hl
2427 } if isPort('z80' 'ez80_z80' 'z180' 'z80n'), notUsed('a'), notUsed('hl')
2429 replace restart {
2430 pop af
2431 ld a,#%1
2432 push af
2433 inc sp
2434 } by {
2435 ld h,#%1
2436 ex (sp),hl
2437 ; common peephole 146 used ex to move #%1 onto the stack.
2438 inc sp
2439 } if isPort('z80' 'ez80_z80' 'z180' 'z80n'), notUsed('a'), notUsed('hl')
2441 replace restart {
2442 ld %1,#%2
2443 ld %3 (%1),a
2445 ld %1,%5
2446 } by {
2447 ld (#%2 + %3),a
2448 ; common peephole 147 directly used #%2 instead of going through %1 using indirect addressing.
2450 ld %1,%5
2453 replace restart {
2454 pop af
2455 ld %1,#%2
2456 ld %3 (%1),%4
2457 ld %1,#%5
2458 } by {
2459 ld a,%4
2460 ld (#%2 + %3),a
2461 ; common peephole 148 used #%2 directly instead of going through %1 using indirect addressing.
2462 pop af
2463 ld %1,#%5
2464 } if notSame(%3 'a')
2466 replace restart {
2467 ld %1,a
2468 bit %2,%1
2469 } by {
2470 bit %2,a
2471 ; common peephole 149 tested bit %2 of a directly instead of going through %1.
2472 } if notUsed(%1)
2474 replace restart {
2475 sbc a,%1
2476 bit 7,a
2477 jp NZ,%2
2478 } by {
2479 sbc a,%1
2480 jp M,%2
2481 ; common peephole 150 used sign flag instead of testing bit 7.
2482 } if isPort('z80' 'ez80_z80' 'z180' 'z80n' 'tlcs90')
2484 replace restart {
2485 ld %1,a
2486 or a,a
2487 jp %3,%4
2488 ld a,%1
2489 } by {
2490 ld %1,a
2491 or a,a
2492 jp %3,%4
2493 ; common peephole 151 used value still in a instead of reloading from %1.
2496 replace {
2497 jp %5
2499 } by {
2500 jp %5
2501 ; common peephole 152 removed unused ret.
2504 replace {
2505 jp %5
2506 ld sp,ix
2507 pop ix
2509 } by {
2510 jp %5
2511 ; common peephole 153 removed unused ret.
2514 replace restart {
2515 %4 a,%1
2516 jp NZ,%2
2517 xor a,a
2518 } by {
2519 %4 a,%1
2520 jp NZ,%2
2521 ; common peephole 154a removed redundant zeroing of a (which has just been tested to be #0x00).
2522 } if same(%4 'or' 'and'), notUsed('f')
2524 replace restart {
2525 %4 a
2526 jp NZ,%2
2527 xor a,a
2528 } by {
2529 %4 a
2530 jp NZ,%2
2531 ; common peephole 154b removed redundant zeroing of a (which has just been tested to be #0x00).
2532 } if same(%4 'inc' 'dec'), notUsed('f')
2534 replace restart {
2535 %4 %1
2536 jp NZ,%2
2537 xor a,a
2538 } by {
2539 %4 %1
2540 jp NZ,%2
2541 ; common peephole 154c reuseded zero of register (which has just been tested to be #0x00).
2542 ld a, %1
2543 } if same(%4 'inc' 'dec'), notUsed('f')
2545 replace restart {
2546 add a, #%1
2547 } by {
2548 ; common peephole 155a turned add into inc.
2549 inc a
2550 } if operandsLiteral(%1), immdInRange(1 1 '+' %1 0 %2), notUsed('cf')
2552 replace restart {
2553 sub a, #%1
2554 } by {
2555 ; common peephole 155b turned sub into dec.
2556 dec a
2557 } if operandsLiteral(%1), immdInRange(1 1 '+' %1 0 %2), notUsed('cf')
2559 replace restart {
2560 add a, #%1
2561 } by {
2562 ; common peephole 155c turned add into dec.
2563 dec a
2564 } if operandsLiteral(%1), immdInRange(0xFF 0xFF '+' %1 0 %2), notUsed('cf')
2566 replace restart {
2567 dec %1
2568 inc %1
2569 } by {
2570 ; common peephole 156a swap dec %1 / inc %1 pair.
2571 inc %1
2572 dec %1
2575 replace restart {
2576 inc %1
2577 dec %1
2578 } by {
2579 ; common peephole 156b removed inc %1 / dec %1 pair.
2580 } if same(%1 'bc' 'de' 'hl' 'ix' 'iy' 'sp')
2582 replace restart {
2583 inc %1
2584 dec %1
2585 } by {
2586 ; common peephole 156c removed inc %1 / dec %1 pair.
2587 } if same(%1 'a' 'b' 'c' 'd' 'e' 'h' 'l' 'ixh' 'ixl' 'iyh' 'iyl'), notUsed('zf' 'vf' 'sf' 'nf' 'hf')
2589 replace restart {
2590 inc %2
2591 inc %1
2592 dec %1
2593 } by {
2594 ; common peephole 156e removed inc %1 / dec %1 pair.
2595 inc %1
2596 inc %2
2597 dec %1
2598 } if same(%1 'bc' 'de' 'hl' 'ix' 'iy' 'sp'), same(%2 'bc' 'de' 'hl' 'ix' 'iy' 'sp'), operandsNotRelated(%1 %2)
2600 replace restart {
2601 jp Z, %2
2602 ld a, #%3
2603 jp %1
2605 ld a, #%4
2607 } by {
2608 ld a, #%3
2609 jp NZ, %1
2611 ld a, #%4
2612 ; common peephole 168z used double assignment in case of Z condition.
2614 } if labelRefCountChange(%2 -1)
2616 replace restart {
2617 jp NZ, %2
2618 ld a, #%3
2619 jp %1
2621 ld a, #%4
2623 } by {
2624 ld a, #%3
2625 jp Z, %1
2627 ld a, #%4
2628 ; common peephole 168nz used double assignment in case of NZ condition.
2630 } if labelRefCountChange(%2 -1)
2632 replace restart {
2633 jp Z, %2
2634 ld a, #%3
2635 jp %1
2637 xor a, a
2639 } by {
2640 ld a, #%3
2641 jp NZ, %1
2642 ; common peephole 169xz used double assignment in case of Z condition.
2644 xor a, a
2646 } if labelRefCountChange(%2 -1)
2648 replace restart {
2649 jp NZ, %2
2650 ld a, #%3
2651 jp %1
2653 xor a, a
2655 } by {
2656 ld a, #%3
2657 jp Z, %1
2658 ; common peephole 169xnz used double assignment in case of NZ condition.
2660 xor a, a
2662 } if labelRefCountChange(%2 -1)
2664 replace restart {
2665 jp Z, %2
2666 ld c, #%3
2667 jp %1
2669 ld c, #%4
2671 } by {
2672 ld c, #%3
2673 jp NZ, %1
2675 ld c, #%4
2676 ; common peephole 170z used double assignment in case of Z condition.
2678 } if labelRefCountChange(%2 -1)
2680 replace restart {
2681 jp NZ, %2
2682 ld c, #%3
2683 jp %1
2685 ld c, #%4
2687 } by {
2688 ld c, #%3
2689 jp Z, %1
2691 ld c, #%4
2692 ; common peephole 170nz used double assignment in case of NZ condition.
2694 } if labelRefCountChange(%2 -1)
2696 replace restart {
2697 jp Z, %2
2698 ld e, #%3
2699 jp %1
2701 ld e, #%4
2703 } by {
2704 ld e, #%3
2705 jp NZ, %1
2707 ld e, #%4
2708 ; common peephole 171z used double assignment in case of Z condition.
2710 } if labelRefCountChange(%2 -1)
2712 replace restart {
2713 jp NZ, %2
2714 ld e, #%3
2715 jp %1
2717 ld e, #%4
2719 } by {
2720 ld e, #%3
2721 jp Z, %1
2723 ld e, #%4
2724 ; common peephole 171nz used double assignment in case of NZ condition.
2726 } if labelRefCountChange(%2 -1)
2728 replace restart {
2729 jp Z, %2
2730 ld l, #%3
2731 jp %1
2733 ld l, #%4
2735 } by {
2736 ld l, #%3
2737 jp NZ, %1
2739 ld l, #%4
2740 ; common peephole 172z used double assignment in case of Z condition.
2742 } if labelRefCountChange(%2 -1)
2744 replace restart {
2745 jp NZ, %2
2746 ld l, #%3
2747 jp %1
2749 ld l, #%4
2751 } by {
2752 ld l, #%3
2753 jp Z, %1
2755 ld l, #%4
2756 ; common peephole 172nz used double assignment in case of NZ condition.
2758 } if labelRefCountChange(%2 -1)
2760 replace restart {
2761 ld %1, %3
2762 ld %2, %4
2763 push %5
2764 } by {
2765 ; common peephole 173 eliminated assignment by pushing %6
2766 push %6
2767 } if canJoinRegs(%2 %1 %7), same(%7 %5), canJoinRegs(%4 %3 %6), notUsed(%5)
2769 // have to be applied late, slows down asm otherwise
2770 replace restart {
2771 ld %1, #%3
2772 ld %2, #%4
2773 } by {
2774 ; ld %1, #%3
2775 ; ld %2, #%4
2776 ld %1, #%3
2777 ; common peephole 174a reused value still in %1.
2778 ld %7, %5
2779 ld %8, %6
2780 } if notSame(%1 'ix' 'iy'), notSame(%2 'ix' 'iy'), canSplitReg(%1 %5 %6), canSplitReg(%2 %7 %8), operandsLiteral(%3 %4), immdInRange(0 0 '-' %3 %4 %9)
2782 // special case for ix/iy, which can't load to/from hl
2783 replace restart {
2784 ld %1, #%3
2785 ld %2, #%4
2786 } by {
2787 ; ld %1, #%3
2788 ; ld %2, #%4
2789 ld %1, #%3
2790 ; common peephole 174b reused value still in %1.
2791 ld %7, %5
2792 ld %8, %6
2793 } if notSame(%1 'hl'), notSame(%2 'hl'), canSplitReg(%1 %5 %6), canSplitReg(%2 %7 %8), operandsLiteral(%3 %4), immdInRange(0 0 '-' %3 %4 %9), notSame(%1 'ix' 'iy'), notSame(%2 'ix' 'iy')
2795 replace restart {
2796 ld %1,%2
2797 ld %2,%1
2798 } by {
2799 ld %1,%2
2800 ; common peephole 176a remove unnecessary load back
2801 } if notVolatile(%1), notVolatile(%2), notSame(%1 '(hl+)' '(hl-)'), notSame(%2 '(hl+)' '(hl-)')
2803 // dec is left there to be removed by other rules
2804 replace restart {
2805 ld (%1), a
2806 inc %1
2807 ld (%1), %2
2808 ld a, (%1)
2809 dec %1
2810 or a, (%1)
2811 } by {
2812 ld (%1), a
2813 inc %1
2814 ld (%1), %2
2815 ; common peephole 176b remove unnecessary load back
2816 or a, %2
2817 dec %1
2818 } if canSplitReg(%1 %0 %0)
2820 replace restart {
2821 ld a, %1
2822 push af
2823 } by {
2824 push %2
2825 ; common peephole 177a replace pushed register pair
2826 } if notUsed('a'), canJoinRegs(%1 '' %2), canSplitReg(%2 %3), same(%3 %1)
2828 replace restart {
2829 push %1
2830 ld (%1), #%2
2831 } by {
2832 ld (%1), #%2
2833 ; common peephole 177b bubbled down push
2834 push %1
2837 replace restart {
2838 push %1
2839 ld a, #%2
2840 ld (%1), a
2841 } by {
2842 ld a, #%2
2843 ld (%1), a
2844 ; common peephole 177c bubbled down push
2845 push %1
2848 replace restart {
2849 inc %3
2850 ld %1, %2 (%3)
2851 } by {
2852 ; common peephole 178 moved increment of %3 after ld instruction
2853 ld %1, %4 (%3)
2854 inc %3
2855 } if operandsNotRelated(%1 %3), immdInRange(-128 127 '+' %2 1 %4)
2857 replace restart {
2858 dec %3
2859 ld %1, %2 (%3)
2860 } by {
2861 ; common peephole 179 moved decrement of %3 after ld instruction
2862 ld %1, %4 (%3)
2863 dec %3
2864 } if operandsNotRelated(%1 %3), immdInRange(-128 127 '-' %2 1 %4)
2866 //next rules optimize code after the call
2867 //replaces lot of `inc sp` by `ld hl,#n; add hl,sp; ld sp,hl`
2868 replace restart {
2869 inc sp
2870 pop %1
2871 ld %2 (%3), %4
2872 } by {
2873 inc sp
2874 ; common peephole 190: move pop instruction after register store
2875 ld %2 (%3), %4
2876 pop %1
2877 } if notSame(%1 %3 %4), operandsNotRelated(%1 %4)
2879 replace restart {
2880 inc sp
2881 ld %1 (%2), %3
2882 } by {
2883 ; common peephole 191a: move register store before stack restore
2884 ld %1 (%2), %3
2885 inc sp
2886 } if notSame(%2 'sp')
2888 replace restart {
2889 inc sp
2890 pop %1
2891 ld %2, %3
2892 } by {
2893 ; common peephole 191b: move register to register copy before SP increment
2894 ld %2, %3
2895 inc sp
2896 pop %1
2897 } if same(%3 'l' 'h'), notSame(%2 'l' 'h'), notUsed('hl'), operandsNotRelated(%1 %2 %3), notSame('sp' %2 %3)
2899 replace restart {
2900 inc sp
2901 ld %1, %2
2902 } by {
2903 ; common peephole 191c: move register store before stack restore
2904 ld %1, %2
2905 inc sp
2906 } if notUsed('hl'), same(%2 'h' 'l' 'sp'), notSame(%1 'h' 'l' 'sp')
2908 replace restart {
2909 inc sp
2910 ld %3, #%1
2911 add %3, sp
2912 ld sp, %3
2913 } by {
2914 ; common peephole 192: increase SP by addition
2915 ld %3, #%2
2916 add %3, sp
2917 ld sp, %3
2918 } if notUsed(%3), same(%3 'hl' 'ix' 'iy'), immdInRange(0 0x7fff '+' %1 1 %2)
2920 replace restart {
2921 inc sp
2922 inc sp
2923 inc sp
2924 inc sp
2925 inc sp
2926 } by {
2927 ; common peephole 193: increase SP by addition
2928 ld hl, #5
2929 add hl, sp
2930 ld sp, hl
2931 } if notUsed('hl')
2933 //next rules optimized some checks
2934 replace restart {
2935 ld a, %1
2936 sub a, #%7
2937 ld a, %2
2938 sbc a, #0x00
2939 ld a, %3
2940 sbc a, #0x00
2941 ld a, %4
2942 sbc a, #0x00
2943 %5 C, %6
2944 } by {
2945 ; common peephole 194-1: symplify 32-bit compare for 8 bit values
2946 ld a, %2
2947 or a, %3
2948 or a, %4
2949 jp NZ, %9
2950 ld a, %1
2951 cp a, #%7
2952 %5 C, %6
2954 } if same(%5 'jr' 'jp' 'call'), notUsed('a'), canAssign('b' %3), canAssign('b' %3), newLabel(%9)
2956 replace restart {
2957 ld a, %1
2958 sub a, #%7
2959 ld a, %2
2960 sbc a, #%8
2961 ld a, %3
2962 sbc a, #0x00
2963 ld a, %4
2964 sbc a, #0x00
2965 %5 C, %6
2966 } by {
2967 ; common peephole 194-2: symplify 32-bit compare for 16 bit values
2968 ld a, %3
2969 or a, %4
2970 jp NZ, %9
2971 ld a, %1
2972 sub a, #%7
2973 ld a, %2
2974 sbc a, #%8
2975 %5 C, %6
2977 } if same(%5 'jr' 'jp' 'call'), notUsed('a'), canAssign('b' %3), newLabel(%9)
2979 replace restart {
2980 ld a, #0xff
2981 cp a, %1
2982 %2 NC, %3
2983 } by {
2984 ; common peephole 195-1: remove always true check
2985 } if same(%2 'jr' 'jp' 'call'), notUsed('a'), labelRefCountChange(%3 -1)
2987 replace restart {
2988 ld a, #0xff
2989 sub a, %1
2990 ld a, #0xff
2991 sbc a, %2
2992 %3 NC, %4
2993 } by {
2994 ; common peephole 195-2: remove always true check
2995 } if same(%3 'jr' 'jp' 'call'), notUsed('a'), labelRefCountChange(%4 -1)
2997 // These ex-generating rules should be among the last ones since ex counts as a read from both hl and de for notUsed().
2998 barrier
3000 replace restart {
3001 ld e,l
3002 ld d,h
3003 } by {
3004 ; common peephole 156 used ex to load hl into de.
3005 ex de,hl
3006 } if isPort('z80' 'ez80_z80' 'z180' 'z80n' 'r2k' 'r2ka' 'r3ka' 'tlcs90'), notUsed('hl')
3008 replace restart {
3009 ld l,e
3010 ld h,d
3011 } by {
3012 ; common peephole 157 used ex to load de into hl.
3013 ex de,hl
3014 } if isPort('z80' 'ez80_z80' 'z180' 'z80n' 'r2k' 'r2ka' 'r3ka' 'tlcs90'), notUsed('de')
3016 // We want this one, even if it doesn't trigger in regression tests, since it is geh last line
3017 // of defence against ld r, r in the compiler. ld r, r is not just an inefficiency, but dangerous
3018 // for Rabbits. ld r, r support is inconsistent among Rabbits, and even otherwise binary-compatible
3019 // Rabbits differ in their support for it.
3020 replace restart
3022 ld %1, %1
3023 } by {
3024 ; common peephole 158 removed redundant ld %1, %1.
3025 } if notVolatile(%1)
3027 barrier
3029 // Should be one of the last ones. Opens the code to further peephole optimization.
3030 replace restart {
3032 } by {
3033 ; common peephole 159 removed unused label %1.
3034 } if labelRefCount(%1 0)
3036 // Ensure that all rules above see only jp, not jr.
3037 // Also do all jump optimizations before replacing by ret.
3038 barrier
3040 replace restart {
3041 jp %5
3042 } by {
3044 ; common peephole 160 replaced jump by return.
3045 } if labelIsReturnOnly(%5), labelRefCountChange(%5 -1)
3047 // SM83 doesn't have ret cc for all flags, but it does for all flags for which is has JP CC.
3048 // This rules can be dangerous for Rabbits: it might trigger a hardware bug in the Rabbit 5000.
3049 replace restart {
3050 jp %1, %5
3051 } by {
3052 ret %1
3053 ; common peephole 161 replaced jump by return.
3054 } if labelIsReturnOnly(%5), labelRefCountChange(%5 -1)
3056 // Replace jp by ret before replacing jp by jr, since using ret can reduce the number of references to jump labels.
3057 barrier
3059 // On Z80 and Z80N, jr is smaller, but slower than jp.
3060 replace restart {
3061 jp %5
3062 } by {
3063 ; common peephole 162 changed absolute to relative unconditional jump.
3064 jr %5
3065 } if optimizeFor('!code-speed'), labelInRange(%5)
3067 // On Z180, eZ80, Rabbit and TLCS-90, jr is smaller, and at least as fast as jp.
3068 replace restart {
3069 jp %5
3070 } by {
3071 ; common peephole 162a changed absolute to relative unconditional jump.
3072 jr %5
3073 } if isPort('z180' 'ez80_z80' 'r2k' 'r2ka' 'r3ka' 'tlcs90' 'sm83' 'r800'), labelInRange(%5)
3075 replace restart {
3076 jp %1, %5
3077 } by {
3078 ; common peephole 163 changed absolute to relative conditional jump.
3079 jr %1, %5
3080 } if same(%1 'C' 'NC' 'NZ' 'Z'), labelInRange(%5)
3082 replace restart {
3083 jr %1, %5
3085 } by {
3086 ; common peephole 164 eliminated relative conditional jump.
3087 } if labelRefCountChange(%5 -1)
3089 replace {
3090 dec b
3091 jr NZ, %5
3092 } by {
3093 ; common peephole 167 used djnz
3094 djnz %5
3095 } if isPort('z80' 'ez80_z80' 'z180' 'z80n' 'r2k' 'r2ka' 'r3ka' 'tlcs90')