1 // peeph.def - Common Z80 and gbz80 peephole rules
3 // These peepholes could be potentially moved to peeph.def, but a GBZ80 expert
4 // Should have a look at them before.
6 // (c) Philipp Klaus Krause (pkk@spth.de, philipp@colecovision.eu) 2006 - 2008
8 // This program is free software; you can redistribute it and/or modify it
9 // under the terms of the GNU General Public License as published by the
10 // Free Software Foundation; either version 2, or (at your option) any
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 ; peephole -1 removed redundant load.
28 // This one doesn't work currently since the peephole optimizer can't match lines generated by multiline macros: Bug #1570701
33 // ; peephole -1a eleminated dead pop.
40 ; peephole 0a removed dead load from %2 into %1.
41 } if notVolatile(%1), notUsed(%1)
42 // Should probably check for notVolatile(%2), too, but gives many false positives and no regression tests fail.
48 ; peephole 0b loaded %2 into a directly instead of going through %1.
50 } if notVolatile(%1), notUsed(%1)
56 ; peephole 0c loaded %2 (%3) into a directly instead of going through %1.
58 } if notVolatile(%1), notUsed(%1)
64 ; peephole 0d loaded %2 into a directly instead of going through %1.
72 ; peephole 0d' loaded %2 into a directly instead of going through %1.
81 ; peephole 0e shifted in a instead of %1.
83 } if notVolatile(%1), notUsed(%1)
91 ; peephole 0f used (hl) in sub directly instead of going through %1.
93 } if notVolatile(%1), notUsed(%1)
102 ; peephole 0g incremented in hl instead of bc.
106 // Catch double and triple incs before later peepholes introduce an ex de,hl in here.
115 ; peephole 0h' incremented in hl instead of de.
127 ; peephole 0h incremented in hl instead of de.
137 ; peephole 0i loaded %2%1 into hl directly instead of going through de.
147 ; peephole 0j used hl for #%2 + %3 instead of bc, not going through a.
150 } if notUsed('a'), notUsed('hl')
157 ; peephole 0j' used hl for #%2 + %3 instead of de, not going through a.
160 } if notUsed('a'), notUsed('hl')
166 ; peephole 0k pushed de directly instead of going through hl.
168 } if notUsed('de'), notUsed('hl')
174 ; peephole 0k' pushed hl directly instead of going through de.
176 } if notUsed('de'), notUsed('hl')
183 ; peephole 0k'' pushed de instead of hl removing a load.
186 } if notUsed('hl'), notUsed('e')
193 ; peephole 0l pushed hl directly instead of going through de.
196 } if notUsed('de'), notUsed('hl')
203 ; peephole 0m pushed bc directly instead of going through hl.
212 ; peephole 0m' pushed bc instead of hl removing a load.
215 } if notUsed('hl'), notUsed('c')
222 ; peephole 0n removed redundant load of a through c.
231 ; peephole 0o used de directly instead of going through bc.
240 ; peephole 0p popped hl directly instead of going through de.
248 ; peephole 0q loaded a into %2 (%3) directly instead of going through %1.
250 } if notVolatile(%1), notUsed(%1)
256 ; peephole 0r loaded %3 from %2 instead of going through %1 (ix).
260 // Don't need to check for volatile, since ix is used for the stack.
266 ; peephole 0s loaded b from %2 (%3) instead of going through %1.
268 } if notVolatile(%1), notUsed(%1)
275 ; peephole 0t loaded %4 from a instead of going through %1.
279 } if notVolatile(%1), operandsNotRelated(%1 %3), operandsNotRelated(%1 %2)
288 ; peephole 0t' loaded %4 from a instead of going through %1.
292 } if notVolatile(%1), operandsNotRelated(%1 %2), operandsNotRelated(%4 %2)
301 ; peephole 0t'' loaded %4 from a instead of going through %1.
311 ; peephole 0u loaded e from (hl) instead of going through %1.
319 ; peephole 0v loaded %2 (%3) from l instead of going through %1.
334 ; peephole 0w shifted (hl) in place.
338 // Don't check for volatile since ix points to the stack.
347 ; peephole 0x pushed de instead of pushing a twice.
350 } if notUsed('d'), notUsed('a')
359 ; peephole 0y pushed bc instead of pushing a twice.
362 } if notUsed('b'), notUsed('a')
368 ; peephole 0z loaded #%1 into d directly instead of going through a.
380 ; peephole 0za pushed %1 (ix), %2(ix) through hl instead of af.
384 } if notUsed('a'), notUsed('hl')
391 ; peephole 0zb pushed hl instead of bc.
395 // Doesn'T work due to bug #1947081
400 // ; peephole 0zc eleminated dead pop/push pair.
407 ; peephole 0zd used hl instead of iy.
410 } if notUsed('iy'), notUsed('hl')
416 ; peephole 0ze used hl instead of iy.
419 } if notUsed('iy'), notUsed('hl')
426 ; peephole 0ze' used hl instead of iy.
430 } if notUsed('iy'), notUsed('h')
436 ; peephole 0zf used hl instead of iy.
439 } if notUsed('iy'), notUsed('hl'), operandsNotRelated(%4 'h'), operandsNotRelated(%4 'l')
446 ; peephole 0zg loaded %1 from (hl) directly instead of going through (de).
455 ; peephole 0zh loaded %1 from (hl) directly instead of going through (bc).
464 ; peephole 0zi incremented in hl instead of bc.
474 ; peephole 0zj tested bit of %1 (%2) directly instead of going through a.
483 ; peephole 0zk stored constant #%1 + %2 into hl directly instead of going through bc.
493 ; peephole 0zk' stored %1 (%2) %3 (%4) into hl directly instead of going through bc.
504 ; peephole 3 removed jp by using inverse jump logic
506 } if labelRefCountChange(%1 -1)
514 ; peephole 4 removed jp by using inverse jump logic
516 } if labelRefCountChange(%1 -1)
524 ; peephole 5 removed jp by using inverse jump logic
526 } if labelRefCountChange(%1 -1)
534 ; peephole 6 removed jp by using inverse jump logic
536 } if labelRefCountChange(%1 -1)
542 ; peephole 7 redirected jump-to-jump at %5 by jump to %6
543 } if labelIsUncondJump(), labelRefCountChange(%5 -1), labelRefCountChange(%6 +1)
549 ; peephole 8 redirected jump-to-jump at %5 by jump to %6
550 } if labelIsUncondJump(), labelRefCountChange(%5 -1), labelRefCountChange(%6 +1)
557 ; peephole 10 removed redundant load of 0 into a.
565 ; peephole 11 combined constant loads into register pair.
573 ; peephole 12 combined constant loads into register pair.
581 ; peephole 13 combined constant loads into register pair.
589 ; peephole 14 removed redundant load from %1 into a.
591 // This gives many false negatives and without the test no problems are encountered in the regression tests
592 // Maybe we can try this after 2.7.0 release
599 ; peephole 15 removed redundant load from a into %1.
601 // This gives many false negatives and without the test no problems are encountered in the regression tests
602 // Maybe we can try this after 2.7.0 release
611 ; peephole 17a removed load by reordering or arguments.
621 ; peephole 17b removed load by reordering or arguments.
631 ; peephole 18 used value still in a instead of loading it from %1.
639 ; peephole 19 removed redundant or after or.
647 ; peephole 19a removed redundant or after or.
655 ; peephole 20 removed redundant or after and.
663 ; peephole 20a removed redundant or after and.
671 ; peephole 21 removed redundant or after xor.
679 ; peephole 21a removed redundant or after xor.
688 ; peephole 23 load value in a first and use it next
689 } if notVolatile(%1 %2)
699 ; peephole 24 removed redundant load from %3%1 into %4%2
700 } if notVolatile(%1 %2 %3 %4)
714 ; peephole 31 moved and pushed arguments c and #%2 through bc instead of pushing them individually.
730 ; peephole 32 moved and pushed arguments e and #%2 through de instead of pushing them individually.
743 ; peephole 33 removed load by replacing sub with cp
755 ; peephole 34 removed load by replacing sub with cp
769 ; peephole 35 replaced sub a,#0xFF by inc a.
778 ; peephole 36 replaced sub a,#0xFF by inc a.
795 ; peephole 37 directly used (%1 + %2) in calculation instead of placing it in bc first.
813 ; peephole 38 directly used (%1 + %2) in calculation instead of placing it in de first.
825 ; peephole 39 replaced zero load, rla by and since rlca writes the same value to carry bit and least significant bit.
835 ; peephole 40 moved %2 directly into de instead of going through %1.
845 ; peephole 41 removed lower part of multibyte addition.
856 ; peephole 42 removed loads by exploiting commutativity of addition.
858 } if notVolatile(%1), notUsed(%1), operandsNotRelated(%2 '(bc)' '(de)')
866 ; peephole 42a removed loads by exploiting commutativity of addition.
869 // Don't need to check for volatile, since ix is used to access the stack.
871 // sdcc does not use the H flag. sla resets it, while add sets it.
872 // To ensure that the state of the H flag is not changed by this
873 // peephole uncomment the add %3, %4 at the end (since it overwrite the H flag).
881 ; peephole 42b shifted in accumulator insted of %1
887 // sdcc does not use the H flag. sla resets it, while add sets it.
888 // To ensure that the state of the H flag is not changed by this
889 // peephole uncomment the add %3, %4 at the end (since it overwrite the H flag).
899 ; peephole 42b' shifted in accumulator insted of %1
917 ; peephole 42c incremented in (hl) instead of going through a.
932 ; peephole 42d decremented in (hl) instead of going through a.
941 ; peephole 43 removed load by exploiting commutativity of addition.
943 } if operandsNotRelated(%2 '(bc)' '(de)')
951 ; peephole 43a removed loads by exploiting commutativity of addition.
962 ; peephole 43b removed loads by exploiting commutativity of addition.
973 ; peephole 43c removed loads by exploiting commutativity of addition.
986 ; peephole 44 removed redundant zeroing of a (which has just been tested to be #0x00).
998 ; peephole 45 replaced constant #0x00 by a (which has just been tested to be #0x00).
1009 ; peephole 46 replaced constant #0x00 by a (which has just been tested to be #0x00).
1020 ; peephole 47 replaced constant #0x00 by a (which has just been tested to be #0x00).
1031 ; peephole 48 replaced constant #0x00 by a (which has just been tested to be #0x00).
1043 // ; peephole 49 shortened or using a (which has just been tested to be #0x00).
1044 //} if operandsNotSame3(%3 '(bc)' '(de)')
1055 // ; peephole 50 shortened or using a (which has just been tested to be #0x00).
1056 //} if operandsNotSame3(%3 '(bc)' '(de)')
1058 // Commented out sine it triggers for %3 od the form (#...)
1068 // ; peephole 51 shortened or using a (which has just been tested to be #0x00).
1070 //if operandsNotSame3(%3 '(bc)' '(de)')
1081 ; peephole 52 shortened or using a (which has just been tested to be #0x00).
1083 //if operandsNotSame3(%2 '(bc)' '(de)')
1095 ; peephole 53 replaced constant #0x00 by a (which has just been tested to be #0x00).
1108 ; peephole 54 replaced constant #0x00 by a (which has just been tested to be #0x00).
1121 ; peephole 55 replaced constant #0x00 by a (which has just been tested to be #0x00).
1134 ; peephole 56 replaced constant #0x00 by a (which has just been tested to be #0x00).
1142 ; peephole 59 moved increment of de to constant.
1150 ; peephole 62 moved increment of bc to constant.
1163 ; peephole 63 moved addition of constant 0x%3%2 to bc to constant.
1171 ; peephole 65 replaced call at end of function by jump.
1182 ; peephole 66 replaced call at end of function by jump moving call beyond pop ix.
1190 ; peephole 67 loaded %2, %3 from a instead of %1.
1194 } if notVolatile(%1)
1203 ; peephole 68 loaded %3 from a instead of %1.
1205 } if notVolatile(%1)
1214 ; peephole 69 used l in or instead of %1.
1216 } if notVolatile(%1)
1225 ; peephole 70 removed load of #%2 into %1 since it's still there.
1226 } if notVolatile(%1), operandsNotRelated(%3 %1)
1232 ; peephole 70a used #%1 from hl for load into de.
1246 ; peephole 71 used ex to get de into hl.
1253 // Lets' hope this is never applied to a jump table. It's fine for calls.
1255 // Should be after 0z.
1264 ; peephole 72 used hl instead of %2 (ix), %1 (ix) to load %4%3.
1267 } if operandsNotRelated('h' %3)
1268 // Don't check for volatile since ix points to the stack.
1279 ; peephole 76 loaded l from a directly instead of going through %1.
1291 ; peephole 77 loaded l from a directly instead of going through %1.
1303 ; peephole 78 removed addition and loads exploiting commutativity of addition.
1311 ; peephole 78a removed ex exploiting commutativity of addition.
1323 ; peephole 79 moved increment to constant.
1328 // These ex-generating rules should be among the last ones since ex counts as a read from both hl and de for notUsed().
1333 ; peephole 80 used ex to load hl into de.
1341 ; peephole 81 used ex to load hl into de.
1349 ; peephole 82 used ex to load de into hl.
1353 // peeph-z80.def - Z80 peephole rules
1356 // (c) Philipp Klaus Krause (pkk@spth.de, philipp@colecovision.eu) 2006 - 2007
1358 // This program is free software; you can redistribute it and/or modify it
1359 // under the terms of the GNU General Public License as published by the
1360 // Free Software Foundation; either version 2, or (at your option) any
1363 // This program is distributed in the hope that it will be useful,
1364 // but WITHOUT ANY WARRANTY; without even the implied warranty of
1365 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1366 // GNU General Public License for more details.
1368 // You should have received a copy of the GNU General Public License
1369 // along with this program; if not, write to the Free Software
1370 // Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1379 ; peephole z1 used #%2 directly instead of going through %1 using indirect addressing.
1391 ; peephole z2 directly used #%2 instead of going through %1 using indirect addressing.
1404 ; peephole z3 used #%2 directly instead of going through %1 using indirect addressing.
1407 } if operandsNotRelated(%3 'a')
1416 ; peephole z4 directly used address #%1 + %2 instead of placing it in bc first.
1425 ld (#%1 + %2 + %6),a
1426 ; peephole z5 directly used address #%1 + %2 + %6 instead of placing it in bc first.
1435 ; peephole z8 moved %1 directly into l instead of going through c.
1447 ; peephole z9 moved hl directly to the stack instead of going through bc.
1459 ; peephole z10 moved hl directly to the stack instead of going through de.
1467 ; peephole z11 replaced jump by return.
1468 } if labelIsReturnOnly(), labelRefCountChange(%5 -1)
1474 ; peephole z11a replaced jump by return.
1475 } if labelIsReturnOnly(), labelRefCountChange(%5 -1)
1477 // Should be one of the last ones. Opens the code to further peephole optimization.
1481 ; peephole z12 removed unused label %1.
1482 } if labelRefCount(%1 0)
1484 // Applying z11 or z11a followed by z12 will often leave a dead ret at the end of the function. Remove it.
1490 ; peephole z13 removed unused ret.
1493 // These four need two be here since the peephole optimizer continues to apply rules further down the file even for replace restart rules.
1500 ; peephole 5' removed jp by using inverse jump logic
1502 } if labelRefCountChange(%1 -1)
1510 ; peephole 5' removed jp by using inverse jump logic
1512 } if labelRefCountChange(%1 -1)
1520 ; peephole 5' removed jp by using inverse jump logic
1522 } if labelRefCountChange(%1 -1)
1530 ; peephole 6' removed jp by using inverse jump logic
1532 } if labelRefCountChange(%1 -1)
1534 // These should be the last rules, so that the peepholes above need to look at jp only.
1539 ; peephole z14 changed absolute to relative unconditional jump.
1546 ; peephole z15 changed absolute to relative conditional jump.
1553 ; peephole z16 changed absolute to relative conditional jump.
1560 ; peephole z17 changed absolute to relative conditional jump.
1567 ; peephole z18 changed absolute to relative conditional jump.