]> git.sur5r.net Git - cc65/blob - src/cc65/codeopt.c
fe647e0f9ef93092229e9839ce37ccb334395675
[cc65] / src / cc65 / codeopt.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 codeopt.c                                 */
4 /*                                                                           */
5 /*                           Optimizer subroutines                           */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2001-2003 Ullrich von Bassewitz                                       */
10 /*               Römerstrasse 52                                             */
11 /*               D-70794 Filderstadt                                         */
12 /* EMail:        uz@cc65.org                                                 */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdlib.h>
37 #include <string.h>
38
39 /* common */
40 #include "abend.h"
41 #include "chartype.h"
42 #include "cpu.h"
43 #include "print.h"
44 #include "xmalloc.h"
45 #include "xsprintf.h"
46
47 /* cc65 */
48 #include "asmlabel.h"
49 #include "codeent.h"
50 #include "codeinfo.h"
51 #include "coptadd.h"
52 #include "coptc02.h"
53 #include "coptcmp.h"
54 #include "coptind.h"
55 #include "coptneg.h"
56 #include "coptpush.h"
57 #include "coptsize.h"
58 #include "coptstop.h"
59 #include "coptstore.h"
60 #include "coptsub.h"
61 #include "copttest.h"
62 #include "error.h"
63 #include "global.h"
64 #include "codeopt.h"
65
66
67
68 /*****************************************************************************/
69 /*                                     Data                                  */
70 /*****************************************************************************/
71
72
73
74 /* Shift types */
75 enum {
76     SHIFT_NONE,
77     SHIFT_ASR_1,
78     SHIFT_ASL_1,
79     SHIFT_LSR_1,
80     SHIFT_LSL_1
81 };
82
83
84
85 /*****************************************************************************/
86 /*                              Optimize shifts                              */
87 /*****************************************************************************/
88
89
90
91 static unsigned OptShift1 (CodeSeg* S)
92 /* A call to the shlaxN routine may get replaced by one or more asl insns
93  * if the value of X is not used later.
94  */
95 {
96     unsigned Changes = 0;
97
98     /* Walk over the entries */
99     unsigned I = 0;
100     while (I < CS_GetEntryCount (S)) {
101
102         /* Get next entry */
103         CodeEntry* E = CS_GetEntry (S, I);
104
105         /* Check for the sequence */
106         if (E->OPC == OP65_JSR                       &&
107             (strncmp (E->Arg, "shlax", 5) == 0 ||
108              strncmp (E->Arg, "aslax", 5) == 0)      &&
109             strlen (E->Arg) == 6                     &&
110             IsDigit (E->Arg[5])                      &&
111             !RegXUsed (S, I+1)) {
112
113             /* Insert shift insns */
114             unsigned Count = E->Arg[5] - '0';
115             while (Count--) {
116                 CodeEntry* X = NewCodeEntry (OP65_ASL, AM65_ACC, "a", 0, E->LI);
117                 CS_InsertEntry (S, X, I+1);
118             }
119
120             /* Delete the call to shlax */
121             CS_DelEntry (S, I);
122
123             /* Remember, we had changes */
124             ++Changes;
125
126         }
127
128         /* Next entry */
129         ++I;
130
131     }
132
133     /* Return the number of changes made */
134     return Changes;
135 }
136
137
138
139 static unsigned OptShift2 (CodeSeg* S)
140 /* A call to the shraxN routine may get replaced by one or more lsr insns
141  * if the value of X is zero.
142  */
143 {
144     unsigned Changes = 0;
145     unsigned I;
146
147     /* Generate register info */
148     CS_GenRegInfo (S);
149
150     /* Walk over the entries */
151     I = 0;
152     while (I < CS_GetEntryCount (S)) {
153
154         /* Get next entry */
155         CodeEntry* E = CS_GetEntry (S, I);
156
157         /* Check for the sequence */
158         if (E->OPC == OP65_JSR                       &&
159             strncmp (E->Arg, "shrax", 5) == 0        &&
160             strlen (E->Arg) == 6                     &&
161             IsDigit (E->Arg[5])                      &&
162             E->RI->In.RegX == 0) {
163
164             /* Insert shift insns */
165             unsigned Count = E->Arg[5] - '0';
166             while (Count--) {
167                 CodeEntry* X = NewCodeEntry (OP65_LSR, AM65_ACC, "a", 0, E->LI);
168                 CS_InsertEntry (S, X, I+1);
169             }
170
171             /* Delete the call to shlax */
172             CS_DelEntry (S, I);
173
174             /* Remember, we had changes */
175             ++Changes;
176
177         }
178
179         /* Next entry */
180         ++I;
181
182     }
183
184     /* Free the register info */
185     CS_FreeRegInfo (S);
186
187     /* Return the number of changes made */
188     return Changes;
189 }
190
191
192
193 static unsigned GetShiftType (const char* Sub)
194 /* Helper function for OptShift3 */
195 {
196     if (*Sub == 'a') {
197         if (strcmp (Sub+1, "slax1") == 0) {
198             return SHIFT_ASL_1;
199         } else if (strcmp (Sub+1, "srax1") == 0) {
200             return SHIFT_ASR_1;
201         }
202     } else if (*Sub == 's') {
203         if (strcmp (Sub+1, "hlax1") == 0) {
204             return SHIFT_LSL_1;
205         } else if (strcmp (Sub+1, "hrax1") == 0) {
206             return SHIFT_LSR_1;
207         }
208     }
209     return SHIFT_NONE;
210 }
211
212
213
214 static unsigned OptShift3 (CodeSeg* S)
215 /* Search for the sequence
216  *
217  *      lda     xxx
218  *      ldx     yyy
219  *      jsr     aslax1/asrax1/shlax1/shrax1
220  *      sta     aaa
221  *      stx     bbb
222  *
223  * and replace it by
224  *
225  *      lda     xxx
226  *      asl     a
227  *      sta     aaa
228  *      lda     yyy
229  *      rol     a
230  *      sta     bbb
231  *
232  * or similar, provided that a/x is not used later
233  */
234 {
235     unsigned Changes = 0;
236
237     /* Walk over the entries */
238     unsigned I = 0;
239     while (I < CS_GetEntryCount (S)) {
240
241         unsigned ShiftType;
242         CodeEntry* L[5];
243
244         /* Get next entry */
245         L[0] = CS_GetEntry (S, I);
246
247         /* Check for the sequence */
248         if (L[0]->OPC == OP65_LDA                               &&
249             (L[0]->AM == AM65_ABS || L[0]->AM == AM65_ZP)       &&
250             CS_GetEntries (S, L+1, I+1, 4)                      &&
251             !CS_RangeHasLabel (S, I+1, 4)                       &&
252             L[1]->OPC == OP65_LDX                               &&
253             (L[1]->AM == AM65_ABS || L[1]->AM == AM65_ZP)       &&
254             L[2]->OPC == OP65_JSR                               &&
255             (ShiftType = GetShiftType (L[2]->Arg)) != SHIFT_NONE&&
256             L[3]->OPC == OP65_STA                               &&
257             (L[3]->AM == AM65_ABS || L[3]->AM == AM65_ZP)       &&
258             L[4]->OPC == OP65_STX                               &&
259             (L[4]->AM == AM65_ABS || L[4]->AM == AM65_ZP)       &&
260             !RegAXUsed (S, I+5)) {
261
262             CodeEntry* X;
263
264             /* Handle the four shift types differently */
265             switch (ShiftType) {
266
267                 case SHIFT_ASR_1:
268                     X = NewCodeEntry (OP65_LDA, L[1]->AM, L[1]->Arg, 0, L[1]->LI);
269                     CS_InsertEntry (S, X, I+5);
270                     X = NewCodeEntry (OP65_CMP, AM65_IMM, "$80", 0, L[2]->LI);
271                     CS_InsertEntry (S, X, I+6);
272                     X = NewCodeEntry (OP65_ROR, AM65_ACC, "a", 0, L[2]->LI);
273                     CS_InsertEntry (S, X, I+7);
274                     X = NewCodeEntry (OP65_STA, L[4]->AM, L[4]->Arg, 0, L[4]->LI);
275                     CS_InsertEntry (S, X, I+8);
276                     X = NewCodeEntry (OP65_LDA, L[0]->AM, L[0]->Arg, 0, L[0]->LI);
277                     CS_InsertEntry (S, X, I+9);
278                     X = NewCodeEntry (OP65_ROR, AM65_ACC, "a", 0, L[2]->LI);
279                     CS_InsertEntry (S, X, I+10);
280                     X = NewCodeEntry (OP65_STA, L[3]->AM, L[3]->Arg, 0, L[3]->LI);
281                     CS_InsertEntry (S, X, I+11);
282                     CS_DelEntries (S, I, 5);
283                     break;
284
285                 case SHIFT_LSR_1:
286                     X = NewCodeEntry (OP65_LDA, L[1]->AM, L[1]->Arg, 0, L[1]->LI);
287                     CS_InsertEntry (S, X, I+5);
288                     X = NewCodeEntry (OP65_LSR, AM65_ACC, "a", 0, L[2]->LI);
289                     CS_InsertEntry (S, X, I+6);
290                     X = NewCodeEntry (OP65_STA, L[4]->AM, L[4]->Arg, 0, L[4]->LI);
291                     CS_InsertEntry (S, X, I+7);
292                     X = NewCodeEntry (OP65_LDA, L[0]->AM, L[0]->Arg, 0, L[0]->LI);
293                     CS_InsertEntry (S, X, I+8);
294                     X = NewCodeEntry (OP65_ROR, AM65_ACC, "a", 0, L[2]->LI);
295                     CS_InsertEntry (S, X, I+9);
296                     X = NewCodeEntry (OP65_STA, L[3]->AM, L[3]->Arg, 0, L[3]->LI);
297                     CS_InsertEntry (S, X, I+10);
298                     CS_DelEntries (S, I, 5);
299                     break;
300
301                 case SHIFT_LSL_1:
302                 case SHIFT_ASL_1:
303                     /* These two are identical */
304                     X = NewCodeEntry (OP65_ASL, AM65_ACC, "a", 0, L[2]->LI);
305                     CS_InsertEntry (S, X, I+1);
306                     X = NewCodeEntry (OP65_STA, L[3]->AM, L[3]->Arg, 0, L[3]->LI);
307                     CS_InsertEntry (S, X, I+2);
308                     X = NewCodeEntry (OP65_LDA, L[1]->AM, L[1]->Arg, 0, L[1]->LI);
309                     CS_InsertEntry (S, X, I+3);
310                     X = NewCodeEntry (OP65_ROL, AM65_ACC, "a", 0, L[2]->LI);
311                     CS_InsertEntry (S, X, I+4);
312                     X = NewCodeEntry (OP65_STA, L[4]->AM, L[4]->Arg, 0, L[4]->LI);
313                     CS_InsertEntry (S, X, I+5);
314                     CS_DelEntries (S, I+6, 4);
315                     break;
316
317             }
318
319             /* Remember, we had changes */
320             ++Changes;
321
322         }
323
324         /* Next entry */
325         ++I;
326
327     }
328
329     /* Return the number of changes made */
330     return Changes;
331 }
332
333
334
335 /*****************************************************************************/
336 /*                              Optimize loads                               */
337 /*****************************************************************************/
338
339
340
341 static unsigned OptLoad1 (CodeSeg* S)
342 /* Search for a call to ldaxysp where X is not used later and replace it by
343  * a load of just the A register.
344  */
345 {
346     unsigned I;
347     unsigned Changes = 0;
348
349     /* Generate register info */
350     CS_GenRegInfo (S);
351
352     /* Walk over the entries */
353     I = 0;
354     while (I < CS_GetEntryCount (S)) {
355
356         CodeEntry* E;
357
358         /* Get next entry */
359         E = CS_GetEntry (S, I);
360
361         /* Check for the sequence */
362         if (CE_IsCallTo (E, "ldaxysp")          &&
363             RegValIsKnown (E->RI->In.RegY)      &&
364             !RegXUsed (S, I+1)) {
365
366             CodeEntry* X;
367
368             /* Reload the Y register */
369             const char* Arg = MakeHexArg (E->RI->In.RegY - 1);
370             X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
371             CS_InsertEntry (S, X, I+1);
372
373             /* Load from stack */
374             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, E->LI);
375             CS_InsertEntry (S, X, I+2);
376
377             /* Now remove the call to the subroutine */
378             CS_DelEntry (S, I);
379
380             /* Remember, we had changes */
381             ++Changes;
382
383         }
384
385         /* Next entry */
386         ++I;
387
388     }
389
390     /* Free the register info */
391     CS_FreeRegInfo (S);
392
393     /* Return the number of changes made */
394     return Changes;
395 }
396
397
398
399 /*****************************************************************************/
400 /*                     Optimize stores through pointers                      */
401 /*****************************************************************************/
402
403
404
405 static unsigned OptPtrStore1Sub (CodeSeg* S, unsigned I, CodeEntry** const L)
406 /* Check if this is one of the allowed suboperation for OptPtrStore1 */
407 {
408     /* Check for a label attached to the entry */
409     if (CE_HasLabel (L[0])) {
410         return 0;
411     }
412
413     /* Check for single insn sub ops */
414     if (L[0]->OPC == OP65_AND                                           ||
415         L[0]->OPC == OP65_EOR                                           ||
416         L[0]->OPC == OP65_ORA                                           ||
417         (L[0]->OPC == OP65_JSR && strncmp (L[0]->Arg, "shlax", 5) == 0) ||
418         (L[0]->OPC == OP65_JSR && strncmp (L[0]->Arg, "shrax", 5) == 0)) {
419
420         /* One insn */
421         return 1;
422
423     } else if (L[0]->OPC == OP65_CLC                      &&
424                (L[1] = CS_GetNextEntry (S, I)) != 0       &&
425                L[1]->OPC == OP65_ADC                      &&
426                !CE_HasLabel (L[1])) {
427         return 2;
428     } else if (L[0]->OPC == OP65_SEC                      &&
429                (L[1] = CS_GetNextEntry (S, I)) != 0       &&
430                L[1]->OPC == OP65_SBC                      &&
431                !CE_HasLabel (L[1])) {
432         return 2;
433     }
434
435
436
437     /* Not found */
438     return 0;
439 }
440
441
442
443 static unsigned OptPtrStore1 (CodeSeg* S)
444 /* Search for the sequence:
445  *
446  *      jsr     pushax
447  *      ldy     xxx
448  *      jsr     ldauidx
449  *      subop
450  *      ldy     yyy
451  *      jsr     staspidx
452  *
453  * and replace it by:
454  *
455  *      sta     ptr1
456  *      stx     ptr1+1
457  *      ldy     xxx
458  *      ldx     #$00
459  *      lda     (ptr1),y
460  *      subop
461  *      ldy     yyy
462  *      sta     (ptr1),y
463  */
464 {
465     unsigned Changes = 0;
466
467     /* Walk over the entries */
468     unsigned I = 0;
469     while (I < CS_GetEntryCount (S)) {
470
471         unsigned K;
472         CodeEntry* L[10];
473
474         /* Get next entry */
475         L[0] = CS_GetEntry (S, I);
476
477         /* Check for the sequence */
478         if (CE_IsCallTo (L[0], "pushax")            &&
479             CS_GetEntries (S, L+1, I+1, 3)          &&
480             L[1]->OPC == OP65_LDY                   &&
481             CE_KnownImm (L[1])                      &&
482             !CE_HasLabel (L[1])                     &&
483             CE_IsCallTo (L[2], "ldauidx")           &&
484             !CE_HasLabel (L[2])                     &&
485             (K = OptPtrStore1Sub (S, I+3, L+3)) > 0 &&
486             CS_GetEntries (S, L+3+K, I+3+K, 2)      &&
487             L[3+K]->OPC == OP65_LDY                 &&
488             CE_KnownImm (L[3+K])                    &&
489             !CE_HasLabel (L[3+K])                   &&
490             CE_IsCallTo (L[4+K], "staspidx")        &&
491             !CE_HasLabel (L[4+K])) {
492
493             CodeEntry* X;
494
495             /* Create and insert the stores */
496             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI);
497             CS_InsertEntry (S, X, I+1);
498
499             X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[0]->LI);
500             CS_InsertEntry (S, X, I+2);
501
502             /* Insert the load from ptr1 */
503             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[3]->LI);
504             CS_InsertEntry (S, X, I+5);
505             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[2]->LI);
506             CS_InsertEntry (S, X, I+6);
507
508             /* Insert the store through ptr1 */
509             X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "ptr1", 0, L[3]->LI);
510             CS_InsertEntry (S, X, I+8+K);
511
512             /* Delete the old code */
513             CS_DelEntry (S, I+9+K);     /* jsr spaspidx */
514             CS_DelEntry (S, I+4);       /* jsr ldauidx */
515             CS_DelEntry (S, I);         /* jsr pushax */
516
517             /* Remember, we had changes */
518             ++Changes;
519
520         }
521
522         /* Next entry */
523         ++I;
524
525     }
526
527     /* Return the number of changes made */
528     return Changes;
529 }
530
531
532
533 static unsigned OptPtrStore2 (CodeSeg* S)
534 /* Search for the sequence:
535  *
536  *      lda     #<(label+0)
537  *      ldx     #>(label+0)
538  *      clc
539  *      adc     xxx
540  *      bcc     L
541  *      inx
542  * L:   jsr     pushax
543  *      ldx     #$00
544  *      lda     yyy
545  *      ldy     #$00
546  *      jsr     staspidx
547  *
548  * and replace it by:
549  *
550  *      ldy     xxx
551  *      ldx     #$00
552  *      lda     yyy
553  *      sta     label,y
554  */
555 {
556     unsigned Changes = 0;
557
558     /* Walk over the entries */
559     unsigned I = 0;
560     while (I < CS_GetEntryCount (S)) {
561
562         CodeEntry* L[11];
563         unsigned Len;
564
565         /* Get next entry */
566         L[0] = CS_GetEntry (S, I);
567
568         /* Check for the sequence */
569         if (L[0]->OPC == OP65_LDA                            &&
570             L[0]->AM == AM65_IMM                             &&
571             CS_GetEntries (S, L+1, I+1, 10)                  &&
572             L[1]->OPC == OP65_LDX                            &&
573             L[1]->AM == AM65_IMM                             &&
574             L[2]->OPC == OP65_CLC                            &&
575             L[3]->OPC == OP65_ADC                            &&
576             (L[3]->AM == AM65_ABS || L[3]->AM == AM65_ZP)    &&
577             (L[4]->OPC == OP65_BCC || L[4]->OPC == OP65_JCC) &&
578             L[4]->JumpTo != 0                                &&
579             L[4]->JumpTo->Owner == L[6]                      &&
580             L[5]->OPC == OP65_INX                            &&
581             CE_IsCallTo (L[6], "pushax")                     &&
582             L[7]->OPC == OP65_LDX                            &&
583             L[8]->OPC == OP65_LDA                            &&
584             L[9]->OPC == OP65_LDY                            &&
585             CE_KnownImm (L[9])                               &&
586             L[9]->Num == 0                                   &&
587             CE_IsCallTo (L[10], "staspidx")                  &&
588             !CS_RangeHasLabel (S, I+1, 5)                    &&
589             !CS_RangeHasLabel (S, I+7, 4)                    &&
590             /* Check the label last because this is quite costly */
591             (Len = strlen (L[0]->Arg)) > 3                   &&
592             L[0]->Arg[0] == '<'                              &&
593             L[0]->Arg[1] == '('                              &&
594             strlen (L[1]->Arg) == Len                        &&
595             L[1]->Arg[0] == '>'                              &&
596             memcmp (L[0]->Arg+1, L[1]->Arg+1, Len-1) == 0) {
597
598             CodeEntry* X;
599             char* Label;
600
601             /* We will create all the new stuff behind the current one so
602              * we keep the line references.
603              */
604             X = NewCodeEntry (OP65_LDY, L[3]->AM, L[3]->Arg, 0, L[0]->LI);
605             CS_InsertEntry (S, X, I+11);
606
607             X = NewCodeEntry (OP65_LDX, L[7]->AM, L[7]->Arg, 0, L[7]->LI);
608             CS_InsertEntry (S, X, I+12);
609
610             X = NewCodeEntry (OP65_LDA, L[8]->AM, L[8]->Arg, 0, L[8]->LI);
611             CS_InsertEntry (S, X, I+13);
612
613             Label = memcpy (xmalloc (Len-2), L[0]->Arg+2, Len-3);
614             Label[Len-3] = '\0';
615             X = NewCodeEntry (OP65_STA, AM65_ABSY, Label, 0, L[10]->LI);
616             CS_InsertEntry (S, X, I+14);
617             xfree (Label);
618
619             /* Remove the old code */
620             CS_DelEntries (S, I, 11);
621
622             /* Remember, we had changes */
623             ++Changes;
624
625         }
626
627         /* Next entry */
628         ++I;
629
630     }
631
632     /* Return the number of changes made */
633     return Changes;
634 }
635
636
637
638 /*****************************************************************************/
639 /*                      Optimize loads through pointers                      */
640 /*****************************************************************************/
641
642
643
644 static unsigned OptPtrLoad1 (CodeSeg* S)
645 /* Search for the sequence:
646  *
647  *      clc
648  *      adc     xxx
649  *      tay
650  *      txa
651  *      adc     yyy
652  *      tax
653  *      tya
654  *      ldy
655  *      jsr     ldauidx
656  *
657  * and replace it by:
658  *
659  *      clc
660  *      adc     xxx
661  *      sta     ptr1
662  *      txa
663  *      adc     yyy
664  *      sta     ptr1+1
665  *      ldy
666  *      ldx     #$00
667  *      lda     (ptr1),y
668  */
669 {
670     unsigned Changes = 0;
671
672     /* Walk over the entries */
673     unsigned I = 0;
674     while (I < CS_GetEntryCount (S)) {
675
676         CodeEntry* L[9];
677
678         /* Get next entry */
679         L[0] = CS_GetEntry (S, I);
680
681         /* Check for the sequence */
682         if (L[0]->OPC == OP65_CLC               &&
683             CS_GetEntries (S, L+1, I+1, 8)      &&
684             L[1]->OPC == OP65_ADC               &&
685             L[2]->OPC == OP65_TAY               &&
686             L[3]->OPC == OP65_TXA               &&
687             L[4]->OPC == OP65_ADC               &&
688             L[5]->OPC == OP65_TAX               &&
689             L[6]->OPC == OP65_TYA               &&
690             L[7]->OPC == OP65_LDY               &&
691             CE_IsCallTo (L[8], "ldauidx")       &&
692             !CS_RangeHasLabel (S, I+1, 8)) {
693
694             CodeEntry* X;
695             CodeEntry* P;
696
697             /* Track the insertion point */
698             unsigned IP = I+2;
699
700             /* sta ptr1 */
701             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[2]->LI);
702             CS_InsertEntry (S, X, IP++);
703
704             /* If the instruction before the clc is a ldx, replace the
705              * txa by an lda with the same location of the ldx. Otherwise
706              * transfer the value in X to A.
707              */
708             if ((P = CS_GetPrevEntry (S, I)) != 0 &&
709                 P->OPC == OP65_LDX                &&
710                 !CE_HasLabel (P)) {
711                 X = NewCodeEntry (OP65_LDA, P->AM, P->Arg, 0, P->LI);
712             } else {
713                 X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, L[3]->LI);
714             }
715             CS_InsertEntry (S, X, IP++);
716
717             /* adc yyy */
718             X = NewCodeEntry (OP65_ADC, L[4]->AM, L[4]->Arg, 0, L[4]->LI);
719             CS_InsertEntry (S, X, IP++);
720
721             /* sta ptr1+1 */
722             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1+1", 0, L[5]->LI);
723             CS_InsertEntry (S, X, IP++);
724
725             /* ldy ... */
726             X = NewCodeEntry (OP65_LDY, L[7]->AM, L[7]->Arg, 0, L[7]->LI);
727             CS_InsertEntry (S, X, IP++);
728
729             /* ldx #$00 */
730             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[8]->LI);
731             CS_InsertEntry (S, X, IP++);
732
733             /* lda (ptr1),y */
734             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[8]->LI);
735             CS_InsertEntry (S, X, IP++);
736
737             /* Remove the old instructions */
738             CS_DelEntries (S, IP, 7);
739
740             /* Remember, we had changes */
741             ++Changes;
742
743         }
744
745         /* Next entry */
746         ++I;
747
748     }
749
750     /* Return the number of changes made */
751     return Changes;
752 }
753
754
755
756 static unsigned OptPtrLoad2 (CodeSeg* S)
757 /* Search for the sequence:
758  *
759  *      adc     xxx
760  *      pha
761  *      txa
762  *      iny
763  *      adc     yyy
764  *      tax
765  *      pla
766  *      ldy
767  *      jsr     ldauidx
768  *
769  * and replace it by:
770  *
771  *      adc     xxx
772  *      sta     ptr1
773  *      txa
774  *      iny
775  *      adc     yyy
776  *      sta     ptr1+1
777  *      ldy
778  *      ldx     #$00
779  *      lda     (ptr1),y
780  */
781 {
782     unsigned Changes = 0;
783
784     /* Walk over the entries */
785     unsigned I = 0;
786     while (I < CS_GetEntryCount (S)) {
787
788         CodeEntry* L[9];
789
790         /* Get next entry */
791         L[0] = CS_GetEntry (S, I);
792
793         /* Check for the sequence */
794         if (L[0]->OPC == OP65_ADC               &&
795             CS_GetEntries (S, L+1, I+1, 8)      &&
796             L[1]->OPC == OP65_PHA               &&
797             L[2]->OPC == OP65_TXA               &&
798             L[3]->OPC == OP65_INY               &&
799             L[4]->OPC == OP65_ADC               &&
800             L[5]->OPC == OP65_TAX               &&
801             L[6]->OPC == OP65_PLA               &&
802             L[7]->OPC == OP65_LDY               &&
803             CE_IsCallTo (L[8], "ldauidx")       &&
804             !CS_RangeHasLabel (S, I+1, 8)) {
805
806             CodeEntry* X;
807
808             /* Store the low byte and remove the PHA instead */
809             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI);
810             CS_InsertEntry (S, X, I+1);
811
812             /* Store the high byte */
813             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1+1", 0, L[4]->LI);
814             CS_InsertEntry (S, X, I+6);
815
816             /* Load high and low byte */
817             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[6]->LI);
818             CS_InsertEntry (S, X, I+10);
819             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[6]->LI);
820             CS_InsertEntry (S, X, I+11);
821
822             /* Delete the old code */
823             CS_DelEntry (S, I+12);      /* jsr ldauidx */
824             CS_DelEntry (S, I+8);       /* pla */
825             CS_DelEntry (S, I+7);       /* tax */
826             CS_DelEntry (S, I+2);       /* pha */
827
828             /* Remember, we had changes */
829             ++Changes;
830
831         }
832
833         /* Next entry */
834         ++I;
835
836     }
837
838     /* Return the number of changes made */
839     return Changes;
840 }
841
842
843
844 static unsigned OptPtrLoad3 (CodeSeg* S)
845 /* Search for the sequence:
846  *
847  *      lda     #<(label+0)
848  *      ldx     #>(label+0)
849  *      clc
850  *      adc     xxx
851  *      bcc     L
852  *      inx
853  * L:   ldy     #$00
854  *      jsr     ldauidx
855  *
856  * and replace it by:
857  *
858  *      ldy     xxx
859  *      ldx     #$00
860  *      lda     label,y
861  */
862 {
863     unsigned Changes = 0;
864
865     /* Walk over the entries */
866     unsigned I = 0;
867     while (I < CS_GetEntryCount (S)) {
868
869         CodeEntry* L[8];
870         unsigned Len;
871
872         /* Get next entry */
873         L[0] = CS_GetEntry (S, I);
874
875         /* Check for the sequence */
876         if (L[0]->OPC == OP65_LDA                            &&
877             L[0]->AM == AM65_IMM                             &&
878             CS_GetEntries (S, L+1, I+1, 7)                   &&
879             L[1]->OPC == OP65_LDX                            &&
880             L[1]->AM == AM65_IMM                             &&
881             L[2]->OPC == OP65_CLC                            &&
882             L[3]->OPC == OP65_ADC                            &&
883             (L[3]->AM == AM65_ABS || L[3]->AM == AM65_ZP)    &&
884             (L[4]->OPC == OP65_BCC || L[4]->OPC == OP65_JCC) &&
885             L[4]->JumpTo != 0                                &&
886             L[4]->JumpTo->Owner == L[6]                      &&
887             L[5]->OPC == OP65_INX                            &&
888             L[6]->OPC == OP65_LDY                            &&
889             CE_KnownImm (L[6])                               &&
890             L[6]->Num == 0                                   &&
891             CE_IsCallTo (L[7], "ldauidx")                    &&
892             !CS_RangeHasLabel (S, I+1, 5)                    &&
893             !CE_HasLabel (L[7])                              &&
894             /* Check the label last because this is quite costly */
895             (Len = strlen (L[0]->Arg)) > 3                   &&
896             L[0]->Arg[0] == '<'                              &&
897             L[0]->Arg[1] == '('                              &&
898             strlen (L[1]->Arg) == Len                        &&
899             L[1]->Arg[0] == '>'                              &&
900             memcmp (L[0]->Arg+1, L[1]->Arg+1, Len-1) == 0) {
901
902             CodeEntry* X;
903             char* Label;
904
905             /* We will create all the new stuff behind the current one so
906              * we keep the line references.
907              */
908             X = NewCodeEntry (OP65_LDY, L[3]->AM, L[3]->Arg, 0, L[0]->LI);
909             CS_InsertEntry (S, X, I+8);
910
911             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[0]->LI);
912             CS_InsertEntry (S, X, I+9);
913
914             Label = memcpy (xmalloc (Len-2), L[0]->Arg+2, Len-3);
915             Label[Len-3] = '\0';
916             X = NewCodeEntry (OP65_LDA, AM65_ABSY, Label, 0, L[0]->LI);
917             CS_InsertEntry (S, X, I+10);
918             xfree (Label);
919
920             /* Remove the old code */
921             CS_DelEntries (S, I, 8);
922
923             /* Remember, we had changes */
924             ++Changes;
925
926         }
927
928         /* Next entry */
929         ++I;
930
931     }
932
933     /* Return the number of changes made */
934     return Changes;
935 }
936
937
938
939 static unsigned OptPtrLoad4 (CodeSeg* S)
940 /* Search for the sequence:
941  *
942  *      lda     #<(label+0)
943  *      ldx     #>(label+0)
944  *      ldy     #$xx
945  *      clc
946  *      adc     (sp),y
947  *      bcc     L
948  *      inx
949  * L:   ldy     #$00
950  *      jsr     ldauidx
951  *
952  * and replace it by:
953  *
954  *      ldy     #$xx
955  *      lda     (sp),y
956  *      tay
957  *      ldx     #$00
958  *      lda     label,y
959  */
960 {
961     unsigned Changes = 0;
962
963     /* Walk over the entries */
964     unsigned I = 0;
965     while (I < CS_GetEntryCount (S)) {
966
967         CodeEntry* L[9];
968         unsigned Len;
969
970         /* Get next entry */
971         L[0] = CS_GetEntry (S, I);
972
973         /* Check for the sequence */
974         if (L[0]->OPC == OP65_LDA                            &&
975             L[0]->AM == AM65_IMM                             &&
976             CS_GetEntries (S, L+1, I+1, 8)                   &&
977             L[1]->OPC == OP65_LDX                            &&
978             L[1]->AM == AM65_IMM                             &&
979             !CE_HasLabel (L[1])                              &&
980             L[2]->OPC == OP65_LDY                            &&
981             CE_KnownImm (L[2])                               &&
982             !CE_HasLabel (L[2])                              &&
983             L[3]->OPC == OP65_CLC                            &&
984             !CE_HasLabel (L[3])                              &&
985             L[4]->OPC == OP65_ADC                            &&
986             L[4]->AM == AM65_ZP_INDY                         &&
987             !CE_HasLabel (L[4])                              &&
988             (L[5]->OPC == OP65_BCC || L[5]->OPC == OP65_JCC) &&
989             L[5]->JumpTo != 0                                &&
990             L[5]->JumpTo->Owner == L[7]                      &&
991             !CE_HasLabel (L[5])                              &&
992             L[6]->OPC == OP65_INX                            &&
993             !CE_HasLabel (L[6])                              &&
994             L[7]->OPC == OP65_LDY                            &&
995             CE_KnownImm (L[7])                               &&
996             L[7]->Num == 0                                   &&
997             CE_IsCallTo (L[8], "ldauidx")                    &&
998             !CE_HasLabel (L[8])                              &&
999             /* Check the label last because this is quite costly */
1000             (Len = strlen (L[0]->Arg)) > 3                   &&
1001             L[0]->Arg[0] == '<'                              &&
1002             L[0]->Arg[1] == '('                              &&
1003             strlen (L[1]->Arg) == Len                        &&
1004             L[1]->Arg[0] == '>'                              &&
1005             memcmp (L[0]->Arg+1, L[1]->Arg+1, Len-1) == 0) {
1006
1007             CodeEntry* X;
1008             char* Label;
1009
1010             /* Add the lda */
1011             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[4]->Arg, 0, L[0]->LI);
1012             CS_InsertEntry (S, X, I+3);
1013
1014             /* Add the tay */
1015             X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, L[0]->LI);
1016             CS_InsertEntry (S, X, I+4);
1017
1018             /* Add the ldx */
1019             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[0]->LI);
1020             CS_InsertEntry (S, X, I+5);
1021
1022             /* Add the lda */
1023             Label = memcpy (xmalloc (Len-2), L[0]->Arg+2, Len-3);
1024             Label[Len-3] = '\0';
1025             X = NewCodeEntry (OP65_LDA, AM65_ABSY, Label, 0, L[0]->LI);
1026             CS_InsertEntry (S, X, I+6);
1027             xfree (Label);
1028
1029             /* Remove the old code */
1030             CS_DelEntries (S, I, 2);
1031             CS_DelEntries (S, I+5, 6);
1032
1033             /* Remember, we had changes */
1034             ++Changes;
1035
1036         }
1037
1038         /* Next entry */
1039         ++I;
1040
1041     }
1042
1043     /* Return the number of changes made */
1044     return Changes;
1045 }
1046
1047
1048
1049 static unsigned OptPtrLoad5 (CodeSeg* S)
1050 /* Search for the sequence:
1051  *
1052  *      lda     zp
1053  *      ldx     zp+1
1054  *      ldy     xx
1055  *      jsr     ldauidx
1056  *
1057  * and replace it by:
1058  *
1059  *      ldy     xx
1060  *      ldx     #$00
1061  *      lda     (zp),y
1062  */
1063 {
1064     unsigned Changes = 0;
1065
1066     /* Walk over the entries */
1067     unsigned I = 0;
1068     while (I < CS_GetEntryCount (S)) {
1069
1070         CodeEntry* L[4];
1071         unsigned Len;
1072
1073         /* Get next entry */
1074         L[0] = CS_GetEntry (S, I);
1075
1076         /* Check for the sequence */
1077         if (L[0]->OPC == OP65_LDA && L[0]->AM == AM65_ZP        &&
1078             CS_GetEntries (S, L+1, I+1, 3)                      &&
1079             !CS_RangeHasLabel (S, I+1, 3)                       &&
1080             L[1]->OPC == OP65_LDX && L[1]->AM == AM65_ZP        &&
1081             (Len = strlen (L[0]->Arg)) > 0                      &&
1082             strncmp (L[0]->Arg, L[1]->Arg, Len) == 0            &&
1083             strcmp (L[1]->Arg + Len, "+1") == 0                 &&
1084             L[2]->OPC == OP65_LDY                               &&
1085             CE_IsCallTo (L[3], "ldauidx")) {
1086
1087             CodeEntry* X;
1088
1089             /* ldx #$00 */
1090             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[3]->LI);
1091             CS_InsertEntry (S, X, I+3);
1092
1093             /* lda (zp),y */
1094             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI);
1095             CS_InsertEntry (S, X, I+4);
1096
1097             /* Remove the old code */
1098             CS_DelEntry (S, I+5);
1099             CS_DelEntries (S, I, 2);
1100
1101             /* Remember, we had changes */
1102             ++Changes;
1103
1104         }
1105
1106         /* Next entry */
1107         ++I;
1108
1109     }
1110
1111     /* Return the number of changes made */
1112     return Changes;
1113 }
1114
1115
1116
1117 static unsigned OptPtrLoad6 (CodeSeg* S)
1118 /* Search for the sequence:
1119  *
1120  *      lda     zp
1121  *      ldx     zp+1
1122  *      ldy     xx
1123  *      jsr     ldaxidx
1124  *
1125  * and replace it by:
1126  *
1127  *      ldy     xx
1128  *      lda     (zp),y
1129  *      tax
1130  *      dey
1131  *      lda     (zp),y
1132  */
1133 {
1134     unsigned Changes = 0;
1135
1136     /* Walk over the entries */
1137     unsigned I = 0;
1138     while (I < CS_GetEntryCount (S)) {
1139
1140         CodeEntry* L[4];
1141         unsigned Len;
1142
1143         /* Get next entry */
1144         L[0] = CS_GetEntry (S, I);
1145
1146         /* Check for the sequence */
1147         if (L[0]->OPC == OP65_LDA && L[0]->AM == AM65_ZP        &&
1148             CS_GetEntries (S, L+1, I+1, 3)                      &&
1149             !CS_RangeHasLabel (S, I+1, 3)                       &&
1150             L[1]->OPC == OP65_LDX && L[1]->AM == AM65_ZP        &&
1151             (Len = strlen (L[0]->Arg)) > 0                      &&
1152             strncmp (L[0]->Arg, L[1]->Arg, Len) == 0            &&
1153             strcmp (L[1]->Arg + Len, "+1") == 0                 &&
1154             L[2]->OPC == OP65_LDY                               &&
1155             CE_IsCallTo (L[3], "ldaxidx")) {
1156
1157             CodeEntry* X;
1158
1159             /* lda (zp),y */
1160             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI);
1161             CS_InsertEntry (S, X, I+4);
1162
1163             /* tax */
1164             X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[3]->LI);
1165             CS_InsertEntry (S, X, I+5);
1166
1167             /* dey */
1168             X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[3]->LI);
1169             CS_InsertEntry (S, X, I+6);
1170
1171             /* lda (zp),y */
1172             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI);
1173             CS_InsertEntry (S, X, I+7);
1174
1175             /* Remove the old code */
1176             CS_DelEntry (S, I+3);
1177             CS_DelEntries (S, I, 2);
1178
1179             /* Remember, we had changes */
1180             ++Changes;
1181
1182         }
1183
1184         /* Next entry */
1185         ++I;
1186
1187     }
1188
1189     /* Return the number of changes made */
1190     return Changes;
1191 }
1192
1193
1194
1195 static unsigned OptPtrLoad7 (CodeSeg* S)
1196 /* Search for the sequence
1197  *
1198  *      ldy     ...
1199  *      jsr     ldauidx
1200  *
1201  * and replace it by:
1202  *
1203  *      ldy     ...
1204  *      stx     ptr1+1
1205  *      sta     ptr1
1206  *      ldx     #$00
1207  *      lda     (ptr1),y
1208  *
1209  * This step must be execute *after* OptPtrLoad1!
1210  */
1211 {
1212     unsigned Changes = 0;
1213
1214     /* Walk over the entries */
1215     unsigned I = 0;
1216     while (I < CS_GetEntryCount (S)) {
1217
1218         CodeEntry* L[2];
1219
1220         /* Get next entry */
1221         L[0] = CS_GetEntry (S, I);
1222
1223         /* Check for the sequence */
1224         if (L[0]->OPC == OP65_LDY               &&
1225             CS_GetEntries (S, L+1, I+1, 1)      &&
1226             CE_IsCallTo (L[1], "ldauidx")       &&
1227             !CE_HasLabel (L[1])) {
1228
1229             CodeEntry* X;
1230
1231             /* Store the high byte */
1232             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI);
1233             CS_InsertEntry (S, X, I+1);
1234
1235             /* Store the low byte */
1236             X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[0]->LI);
1237             CS_InsertEntry (S, X, I+2);
1238
1239             /* Delete the call to ldauidx */
1240             CS_DelEntry (S, I+3);
1241
1242             /* Load the high and low byte */
1243             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[0]->LI);
1244             CS_InsertEntry (S, X, I+3);
1245             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[0]->LI);
1246             CS_InsertEntry (S, X, I+4);
1247
1248             /* Remember, we had changes */
1249             ++Changes;
1250
1251         }
1252
1253         /* Next entry */
1254         ++I;
1255
1256     }
1257
1258     /* Return the number of changes made */
1259     return Changes;
1260 }
1261
1262
1263
1264 /*****************************************************************************/
1265 /*                            Decouple operations                            */
1266 /*****************************************************************************/
1267
1268
1269
1270 static unsigned OptDecouple (CodeSeg* S)
1271 /* Decouple operations, that is, do the following replacements:
1272  *
1273  *   dex        -> ldx #imm
1274  *   inx        -> ldx #imm
1275  *   dey        -> ldy #imm
1276  *   iny        -> ldy #imm
1277  *   tax        -> ldx #imm
1278  *   txa        -> lda #imm
1279  *   tay        -> ldy #imm
1280  *   tya        -> lda #imm
1281  *   lda zp     -> lda #imm
1282  *   ldx zp     -> ldx #imm
1283  *   ldy zp     -> ldy #imm
1284  *
1285  * Provided that the register values are known of course.
1286  */
1287 {
1288     unsigned Changes = 0;
1289     unsigned I;
1290
1291     /* Generate register info for the following step */
1292     CS_GenRegInfo (S);
1293
1294     /* Walk over the entries */
1295     I = 0;
1296     while (I < CS_GetEntryCount (S)) {
1297
1298         const char* Arg;
1299
1300         /* Get next entry and it's input register values */
1301         CodeEntry* E = CS_GetEntry (S, I);
1302         const RegContents* In = &E->RI->In;
1303
1304         /* Assume we have no replacement */
1305         CodeEntry* X = 0;
1306
1307         /* Check the instruction */
1308         switch (E->OPC) {
1309
1310             case OP65_DEA:
1311                 if (RegValIsKnown (In->RegA)) {
1312                     Arg = MakeHexArg ((In->RegA - 1) & 0xFF);
1313                     X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
1314                 }
1315                 break;
1316
1317             case OP65_DEX:
1318                 if (RegValIsKnown (In->RegX)) {
1319                     Arg = MakeHexArg ((In->RegX - 1) & 0xFF);
1320                     X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
1321                 }
1322                 break;
1323
1324             case OP65_DEY:
1325                 if (RegValIsKnown (In->RegY)) {
1326                     Arg = MakeHexArg ((In->RegY - 1) & 0xFF);
1327                     X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
1328                 }
1329                 break;
1330
1331             case OP65_INA:
1332                 if (RegValIsKnown (In->RegA)) {
1333                     Arg = MakeHexArg ((In->RegA + 1) & 0xFF);
1334                     X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
1335                 }
1336                 break;
1337
1338             case OP65_INX:
1339                 if (RegValIsKnown (In->RegX)) {
1340                     Arg = MakeHexArg ((In->RegX + 1) & 0xFF);
1341                     X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
1342                 }
1343                 break;
1344
1345             case OP65_INY:
1346                 if (RegValIsKnown (In->RegY)) {
1347                     Arg = MakeHexArg ((In->RegY + 1) & 0xFF);
1348                     X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
1349                 }
1350                 break;
1351
1352             case OP65_LDA:
1353                 if (E->AM == AM65_ZP) {
1354                     switch (GetKnownReg (E->Use & REG_ZP, In)) {
1355                         case REG_TMP1:
1356                             Arg = MakeHexArg (In->Tmp1);
1357                             X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
1358                             break;
1359
1360                         case REG_PTR1_LO:
1361                             Arg = MakeHexArg (In->Ptr1Lo);
1362                             X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
1363                             break;
1364
1365                         case REG_PTR1_HI:
1366                             Arg = MakeHexArg (In->Ptr1Hi);
1367                             X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
1368                             break;
1369
1370                         case REG_SREG_LO:
1371                             Arg = MakeHexArg (In->SRegLo);
1372                             X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
1373                             break;
1374
1375                         case REG_SREG_HI:
1376                             Arg = MakeHexArg (In->SRegHi);
1377                             X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
1378                             break;
1379                     }
1380                 }
1381                 break;
1382
1383             case OP65_LDX:
1384                 if (E->AM == AM65_ZP) {
1385                     switch (GetKnownReg (E->Use & REG_ZP, In)) {
1386                         case REG_TMP1:
1387                             Arg = MakeHexArg (In->Tmp1);
1388                             X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
1389                             break;
1390
1391                         case REG_PTR1_LO:
1392                             Arg = MakeHexArg (In->Ptr1Lo);
1393                             X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
1394                             break;
1395
1396                         case REG_PTR1_HI:
1397                             Arg = MakeHexArg (In->Ptr1Hi);
1398                             X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
1399                             break;
1400
1401                         case REG_SREG_LO:
1402                             Arg = MakeHexArg (In->SRegLo);
1403                             X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
1404                             break;
1405
1406                         case REG_SREG_HI:
1407                             Arg = MakeHexArg (In->SRegHi);
1408                             X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
1409                             break;
1410                     }
1411                 }
1412                 break;
1413
1414             case OP65_LDY:
1415                 if (E->AM == AM65_ZP) {
1416                     switch (GetKnownReg (E->Use, In)) {
1417                         case REG_TMP1:
1418                             Arg = MakeHexArg (In->Tmp1);
1419                             X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
1420                             break;
1421
1422                         case REG_PTR1_LO:
1423                             Arg = MakeHexArg (In->Ptr1Lo);
1424                             X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
1425                             break;
1426
1427                         case REG_PTR1_HI:
1428                             Arg = MakeHexArg (In->Ptr1Hi);
1429                             X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
1430                             break;
1431
1432                         case REG_SREG_LO:
1433                             Arg = MakeHexArg (In->SRegLo);
1434                             X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
1435                             break;
1436
1437                         case REG_SREG_HI:
1438                             Arg = MakeHexArg (In->SRegHi);
1439                             X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
1440                             break;
1441                     }
1442                 }
1443                 break;
1444
1445             case OP65_TAX:
1446                 if (E->RI->In.RegA >= 0) {
1447                     Arg = MakeHexArg (In->RegA);
1448                     X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
1449                 }
1450                 break;
1451
1452             case OP65_TAY:
1453                 if (E->RI->In.RegA >= 0) {
1454                     Arg = MakeHexArg (In->RegA);
1455                     X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
1456                 }
1457                 break;
1458
1459             case OP65_TXA:
1460                 if (E->RI->In.RegX >= 0) {
1461                     Arg = MakeHexArg (In->RegX);
1462                     X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
1463                 }
1464                 break;
1465
1466             case OP65_TYA:
1467                 if (E->RI->In.RegY >= 0) {
1468                     Arg = MakeHexArg (In->RegY);
1469                     X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
1470                 }
1471                 break;
1472
1473             default:
1474                 /* Avoid gcc warnings */
1475                 break;
1476
1477         }
1478
1479         /* Insert the replacement if we have one */
1480         if (X) {
1481             CS_InsertEntry (S, X, I+1);
1482             CS_DelEntry (S, I);
1483             ++Changes;
1484         }
1485
1486         /* Next entry */
1487         ++I;
1488
1489     }
1490
1491     /* Free register info */
1492     CS_FreeRegInfo (S);
1493
1494     /* Return the number of changes made */
1495     return Changes;
1496 }
1497
1498
1499
1500 /*****************************************************************************/
1501 /*                              struct OptFunc                               */
1502 /*****************************************************************************/
1503
1504
1505
1506 typedef struct OptFunc OptFunc;
1507 struct OptFunc {
1508     unsigned       (*Func) (CodeSeg*);  /* Optimizer function */
1509     const char*    Name;                /* Name of the function/group */
1510     unsigned       CodeSizeFactor;      /* Code size factor for this opt func */
1511     unsigned long  TotalRuns;           /* Total number of runs */
1512     unsigned long  LastRuns;            /* Last number of runs */
1513     unsigned long  TotalChanges;        /* Total number of changes */
1514     unsigned long  LastChanges;         /* Last number of changes */
1515     char           Disabled;            /* True if function disabled */
1516 };
1517
1518
1519
1520 /*****************************************************************************/
1521 /*                                   Code                                    */
1522 /*****************************************************************************/
1523
1524
1525
1526 /* A list of all the function descriptions */
1527 static OptFunc DOpt65C02BitOps  = { Opt65C02BitOps,  "Opt65C02BitOps",   66, 0, 0, 0, 0, 0 };
1528 static OptFunc DOpt65C02Ind     = { Opt65C02Ind,     "Opt65C02Ind",     100, 0, 0, 0, 0, 0 };
1529 static OptFunc DOpt65C02Stores  = { Opt65C02Stores,  "Opt65C02Stores",  100, 0, 0, 0, 0, 0 };
1530 static OptFunc DOptAdd1         = { OptAdd1,         "OptAdd1",         125, 0, 0, 0, 0, 0 };
1531 static OptFunc DOptAdd2         = { OptAdd2,         "OptAdd2",         200, 0, 0, 0, 0, 0 };
1532 static OptFunc DOptAdd3         = { OptAdd3,         "OptAdd3",          90, 0, 0, 0, 0, 0 };
1533 static OptFunc DOptAdd4         = { OptAdd4,         "OptAdd4",         100, 0, 0, 0, 0, 0 };
1534 static OptFunc DOptAdd5         = { OptAdd5,         "OptAdd5",          40, 0, 0, 0, 0, 0 };
1535 static OptFunc DOptBoolTrans    = { OptBoolTrans,    "OptBoolTrans",    100, 0, 0, 0, 0, 0 };
1536 static OptFunc DOptBranchDist   = { OptBranchDist,   "OptBranchDist",     0, 0, 0, 0, 0, 0 };
1537 static OptFunc DOptCmp1         = { OptCmp1,         "OptCmp1",          85, 0, 0, 0, 0, 0 };
1538 static OptFunc DOptCmp2         = { OptCmp2,         "OptCmp2",          75, 0, 0, 0, 0, 0 };
1539 static OptFunc DOptCmp3         = { OptCmp3,         "OptCmp3",          75, 0, 0, 0, 0, 0 };
1540 static OptFunc DOptCmp4         = { OptCmp4,         "OptCmp4",         100, 0, 0, 0, 0, 0 };
1541 static OptFunc DOptCmp5         = { OptCmp5,         "OptCmp5",         100, 0, 0, 0, 0, 0 };
1542 static OptFunc DOptCmp6         = { OptCmp6,         "OptCmp6",          85, 0, 0, 0, 0, 0 };
1543 static OptFunc DOptCmp7         = { OptCmp7,         "OptCmp7",          50, 0, 0, 0, 0, 0 };
1544 static OptFunc DOptCondBranches = { OptCondBranches, "OptCondBranches",  80, 0, 0, 0, 0, 0 };
1545 static OptFunc DOptDeadCode     = { OptDeadCode,     "OptDeadCode",     100, 0, 0, 0, 0, 0 };
1546 static OptFunc DOptDeadJumps    = { OptDeadJumps,    "OptDeadJumps",    100, 0, 0, 0, 0, 0 };
1547 static OptFunc DOptDecouple     = { OptDecouple,     "OptDecouple",     100, 0, 0, 0, 0, 0 };
1548 static OptFunc DOptDupLoads     = { OptDupLoads,     "OptDupLoads",       0, 0, 0, 0, 0, 0 };
1549 static OptFunc DOptJumpCascades = { OptJumpCascades, "OptJumpCascades", 100, 0, 0, 0, 0, 0 };
1550 static OptFunc DOptJumpTarget   = { OptJumpTarget,   "OptJumpTarget",   100, 0, 0, 0, 0, 0 };
1551 static OptFunc DOptLoad1        = { OptLoad1,        "OptLoad1",        100, 0, 0, 0, 0, 0 };
1552 static OptFunc DOptRTS          = { OptRTS,          "OptRTS",          100, 0, 0, 0, 0, 0 };
1553 static OptFunc DOptRTSJumps1    = { OptRTSJumps1,    "OptRTSJumps1",    100, 0, 0, 0, 0, 0 };
1554 static OptFunc DOptRTSJumps2    = { OptRTSJumps2,    "OptRTSJumps2",    100, 0, 0, 0, 0, 0 };
1555 static OptFunc DOptNegA1        = { OptNegA1,        "OptNegA1",        100, 0, 0, 0, 0, 0 };
1556 static OptFunc DOptNegA2        = { OptNegA2,        "OptNegA2",        100, 0, 0, 0, 0, 0 };
1557 static OptFunc DOptNegAX1       = { OptNegAX1,       "OptNegAX1",       100, 0, 0, 0, 0, 0 };
1558 static OptFunc DOptNegAX2       = { OptNegAX2,       "OptNegAX2",       100, 0, 0, 0, 0, 0 };
1559 static OptFunc DOptNegAX3       = { OptNegAX3,       "OptNegAX3",       100, 0, 0, 0, 0, 0 };
1560 static OptFunc DOptNegAX4       = { OptNegAX4,       "OptNegAX4",       100, 0, 0, 0, 0, 0 };
1561 static OptFunc DOptPrecalc      = { OptPrecalc,      "OptPrecalc",      100, 0, 0, 0, 0, 0 };
1562 static OptFunc DOptPtrLoad1     = { OptPtrLoad1,     "OptPtrLoad1",     100, 0, 0, 0, 0, 0 };
1563 static OptFunc DOptPtrLoad2     = { OptPtrLoad2,     "OptPtrLoad2",     100, 0, 0, 0, 0, 0 };
1564 static OptFunc DOptPtrLoad3     = { OptPtrLoad3,     "OptPtrLoad3",     100, 0, 0, 0, 0, 0 };
1565 static OptFunc DOptPtrLoad4     = { OptPtrLoad4,     "OptPtrLoad4",     100, 0, 0, 0, 0, 0 };
1566 static OptFunc DOptPtrLoad5     = { OptPtrLoad5,     "OptPtrLoad5",      65, 0, 0, 0, 0, 0 };
1567 static OptFunc DOptPtrLoad6     = { OptPtrLoad6,     "OptPtrLoad6",      86, 0, 0, 0, 0, 0 };
1568 static OptFunc DOptPtrLoad7     = { OptPtrLoad7,     "OptPtrLoad7",     100, 0, 0, 0, 0, 0 };
1569 static OptFunc DOptPtrStore1    = { OptPtrStore1,    "OptPtrStore1",    100, 0, 0, 0, 0, 0 };
1570 static OptFunc DOptPtrStore2    = { OptPtrStore2,    "OptPtrStore2",     40, 0, 0, 0, 0, 0 };
1571 static OptFunc DOptPush1        = { OptPush1,        "OptPush1",         65, 0, 0, 0, 0, 0 };
1572 static OptFunc DOptPush2        = { OptPush2,        "OptPush2",         50, 0, 0, 0, 0, 0 };
1573 static OptFunc DOptPushPop      = { OptPushPop,      "OptPushPop",        0, 0, 0, 0, 0, 0 };
1574 static OptFunc DOptShift1       = { OptShift1,       "OptShift1",       100, 0, 0, 0, 0, 0 };
1575 static OptFunc DOptShift2       = { OptShift2,       "OptShift2",       100, 0, 0, 0, 0, 0 };
1576 static OptFunc DOptShift3       = { OptShift3,       "OptShift3",       110, 0, 0, 0, 0, 0 };
1577 static OptFunc DOptSize1        = { OptSize1,        "OptSize1",        100, 0, 0, 0, 0, 0 };
1578 static OptFunc DOptSize2        = { OptSize2,        "OptSize2",        100, 0, 0, 0, 0, 0 };
1579 static OptFunc DOptStackOps     = { OptStackOps,     "OptStackOps",     100, 0, 0, 0, 0, 0 };
1580 static OptFunc DOptStore1       = { OptStore1,       "OptStore1",        70, 0, 0, 0, 0, 0 };
1581 static OptFunc DOptStore2       = { OptStore2,       "OptStore2",       220, 0, 0, 0, 0, 0 };
1582 static OptFunc DOptStore3       = { OptStore3,       "OptStore3",       120, 0, 0, 0, 0, 0 };
1583 static OptFunc DOptStore4       = { OptStore4,       "OptStore4",        50, 0, 0, 0, 0, 0 };
1584 static OptFunc DOptStoreLoad    = { OptStoreLoad,    "OptStoreLoad",      0, 0, 0, 0, 0, 0 };
1585 static OptFunc DOptSub1         = { OptSub1,         "OptSub1",         100, 0, 0, 0, 0, 0 };
1586 static OptFunc DOptSub2         = { OptSub2,         "OptSub2",         100, 0, 0, 0, 0, 0 };
1587 static OptFunc DOptTest1        = { OptTest1,        "OptTest1",        100, 0, 0, 0, 0, 0 };
1588 static OptFunc DOptTransfers1   = { OptTransfers1,   "OptTransfers1",     0, 0, 0, 0, 0, 0 };
1589 static OptFunc DOptTransfers2   = { OptTransfers2,   "OptTransfers2",    60, 0, 0, 0, 0, 0 };
1590 static OptFunc DOptUnusedLoads  = { OptUnusedLoads,  "OptUnusedLoads",    0, 0, 0, 0, 0, 0 };
1591 static OptFunc DOptUnusedStores = { OptUnusedStores, "OptUnusedStores",   0, 0, 0, 0, 0, 0 };
1592
1593
1594 /* Table containing all the steps in alphabetical order */
1595 static OptFunc* OptFuncs[] = {
1596     &DOpt65C02BitOps,
1597     &DOpt65C02Ind,
1598     &DOpt65C02Stores,
1599     &DOptAdd1,
1600     &DOptAdd2,
1601     &DOptAdd3,
1602     &DOptAdd4,
1603     &DOptAdd5,
1604     &DOptBoolTrans,
1605     &DOptBranchDist,
1606     &DOptCmp1,
1607     &DOptCmp2,
1608     &DOptCmp3,
1609     &DOptCmp4,
1610     &DOptCmp5,
1611     &DOptCmp6,
1612     &DOptCmp7,
1613     &DOptCondBranches,
1614     &DOptDeadCode,
1615     &DOptDeadJumps,
1616     &DOptDecouple,
1617     &DOptDupLoads,
1618     &DOptJumpCascades,
1619     &DOptJumpTarget,
1620     &DOptLoad1,
1621     &DOptNegA1,
1622     &DOptNegA2,
1623     &DOptNegAX1,
1624     &DOptNegAX2,
1625     &DOptNegAX3,
1626     &DOptNegAX4,
1627     &DOptPrecalc,
1628     &DOptPtrLoad1,
1629     &DOptPtrLoad2,
1630     &DOptPtrLoad3,
1631     &DOptPtrLoad4,
1632     &DOptPtrLoad5,
1633     &DOptPtrLoad6,
1634     &DOptPtrLoad7,
1635     &DOptPtrStore1,
1636     &DOptPtrStore2,
1637     &DOptPush1,
1638     &DOptPush2,
1639     &DOptPushPop,
1640     &DOptRTS,
1641     &DOptRTSJumps1,
1642     &DOptRTSJumps2,
1643     &DOptShift1,
1644     &DOptShift2,
1645     &DOptShift3,
1646     &DOptSize1,
1647     &DOptSize2,
1648     &DOptStackOps,
1649     &DOptStore1,
1650     &DOptStore2,
1651     &DOptStore3,
1652     &DOptStore4,
1653     &DOptStoreLoad,
1654     &DOptSub1,
1655     &DOptSub2,
1656     &DOptTest1,
1657     &DOptTransfers1,
1658     &DOptTransfers2,
1659     &DOptUnusedLoads,
1660     &DOptUnusedStores,
1661 };
1662 #define OPTFUNC_COUNT  (sizeof(OptFuncs) / sizeof(OptFuncs[0]))
1663
1664
1665
1666 static int CmpOptStep (const void* Key, const void* Func)
1667 /* Compare function for bsearch */
1668 {
1669     return strcmp (Key, (*(const OptFunc**)Func)->Name);
1670 }
1671
1672
1673
1674 static OptFunc* FindOptFunc (const char* Name)
1675 /* Find an optimizer step by name in the table and return a pointer. Return
1676  * NULL if no such step is found.
1677  */
1678 {
1679     /* Search for the function in the list */
1680     OptFunc** O = bsearch (Name, OptFuncs, OPTFUNC_COUNT, sizeof (OptFuncs[0]), CmpOptStep);
1681     return O? *O : 0;
1682 }
1683
1684
1685
1686 static OptFunc* GetOptFunc (const char* Name)
1687 /* Find an optimizer step by name in the table and return a pointer. Print an
1688  * error and call AbEnd if not found.
1689  */
1690 {
1691     /* Search for the function in the list */
1692     OptFunc* F = FindOptFunc (Name);
1693     if (F == 0) {
1694         /* Not found */
1695         AbEnd ("Optimization step `%s' not found", Name);
1696     }
1697     return F;
1698 }
1699
1700
1701
1702 void DisableOpt (const char* Name)
1703 /* Disable the optimization with the given name */
1704 {
1705     if (strcmp (Name, "any") == 0) {
1706         unsigned I;
1707         for (I = 0; I < OPTFUNC_COUNT; ++I) {
1708             OptFuncs[I]->Disabled = 1;
1709         }
1710     } else {
1711         GetOptFunc(Name)->Disabled = 1;
1712     }
1713 }
1714
1715
1716
1717 void EnableOpt (const char* Name)
1718 /* Enable the optimization with the given name */
1719 {
1720     if (strcmp (Name, "any") == 0) {
1721         unsigned I;
1722         for (I = 0; I < OPTFUNC_COUNT; ++I) {
1723             OptFuncs[I]->Disabled = 0;
1724         }
1725     } else {
1726         GetOptFunc(Name)->Disabled = 0;
1727     }
1728 }
1729
1730
1731
1732 void ListOptSteps (FILE* F)
1733 /* List all optimization steps */
1734 {
1735     unsigned I;
1736     for (I = 0; I < OPTFUNC_COUNT; ++I) {
1737         fprintf (F, "%s\n", OptFuncs[I]->Name);
1738     }
1739 }
1740
1741
1742
1743 static void ReadOptStats (const char* Name)
1744 /* Read the optimizer statistics file */
1745 {
1746     char Buf [256];
1747     unsigned Lines;
1748
1749     /* Try to open the file */
1750     FILE* F = fopen (Name, "r");
1751     if (F == 0) {
1752         /* Ignore the error */
1753         return;
1754     }
1755
1756     /* Read and parse the lines */
1757     Lines = 0;
1758     while (fgets (Buf, sizeof (Buf), F) != 0) {
1759
1760         char* B;
1761         unsigned Len;
1762         OptFunc* Func;
1763
1764         /* Fields */
1765         char Name[32];
1766         unsigned long  TotalRuns;
1767         unsigned long  TotalChanges;
1768
1769         /* Count lines */
1770         ++Lines;
1771
1772         /* Remove trailing white space including the line terminator */
1773         B = Buf;
1774         Len = strlen (B);
1775         while (Len > 0 && IsSpace (B[Len-1])) {
1776             --Len;
1777         }
1778         B[Len] = '\0';
1779
1780         /* Remove leading whitespace */
1781         while (IsSpace (*B)) {
1782             ++B;
1783         }
1784
1785         /* Check for empty and comment lines */
1786         if (*B == '\0' || *B == ';' || *B == '#') {
1787             continue;
1788         }
1789
1790         /* Parse the line */
1791         if (sscanf (B, "%31s %lu %*u %lu %*u", Name, &TotalRuns, &TotalChanges) != 3) {
1792             /* Syntax error */
1793             continue;
1794         }
1795
1796         /* Search for the optimizer step. */
1797         Func = FindOptFunc (Name);
1798         if (Func == 0) {
1799             /* Not found */
1800             continue;
1801         }
1802
1803         /* Found the step, set the fields */
1804         Func->TotalRuns    = TotalRuns;
1805         Func->TotalChanges = TotalChanges;
1806
1807     }
1808
1809     /* Close the file, ignore errors here. */
1810     fclose (F);
1811 }
1812
1813
1814
1815 static void WriteOptStats (const char* Name)
1816 /* Write the optimizer statistics file */
1817 {
1818     unsigned I;
1819
1820     /* Try to open the file */
1821     FILE* F = fopen (Name, "w");
1822     if (F == 0) {
1823         /* Ignore the error */
1824         return;
1825     }
1826
1827     /* Write a header */
1828     fprintf (F,
1829              "; Optimizer               Total      Last       Total      Last\n"
1830              ";   Step                  Runs       Runs        Chg       Chg\n");
1831
1832
1833     /* Write the data */
1834     for (I = 0; I < OPTFUNC_COUNT; ++I) {
1835         const OptFunc* O = OptFuncs[I];
1836         fprintf (F,
1837                  "%-20s %10lu %10lu %10lu %10lu\n",
1838                  O->Name,
1839                  O->TotalRuns,
1840                  O->LastRuns,
1841                  O->TotalChanges,
1842                  O->LastChanges);
1843     }
1844
1845     /* Close the file, ignore errors here. */
1846     fclose (F);
1847 }
1848
1849
1850
1851 static unsigned RunOptFunc (CodeSeg* S, OptFunc* F, unsigned Max)
1852 /* Run one optimizer function Max times or until there are no more changes */
1853 {
1854     unsigned Changes, C;
1855
1856     /* Don't run the function if it is disabled or if it is prohibited by the
1857      * code size factor
1858      */
1859     if (F->Disabled || F->CodeSizeFactor > CodeSizeFactor) {
1860         return 0;
1861     }
1862
1863     /* Run this until there are no more changes */
1864     Changes = 0;
1865     do {
1866
1867         /* Run the function */
1868         C = F->Func (S);
1869         Changes += C;
1870
1871         /* Do statistics */
1872         ++F->TotalRuns;
1873         ++F->LastRuns;
1874         F->TotalChanges += C;
1875         F->LastChanges  += C;
1876
1877     } while (--Max && C > 0);
1878
1879     /* Return the number of changes */
1880     return Changes;
1881 }
1882
1883
1884
1885 static unsigned RunOptGroup1 (CodeSeg* S)
1886 /* Run the first group of optimization steps. These steps translate known
1887  * patterns emitted by the code generator into more optimal patterns. Order
1888  * of the steps is important, because some of the steps done earlier cover
1889  * the same patterns as later steps as subpatterns.
1890  */
1891 {
1892     unsigned Changes = 0;
1893
1894     Changes += RunOptFunc (S, &DOptPtrStore1, 1);
1895     Changes += RunOptFunc (S, &DOptPtrStore2, 1);
1896     Changes += RunOptFunc (S, &DOptPtrLoad1, 1);
1897     Changes += RunOptFunc (S, &DOptPtrLoad2, 1);
1898     Changes += RunOptFunc (S, &DOptPtrLoad3, 1);
1899     Changes += RunOptFunc (S, &DOptPtrLoad4, 1);
1900     Changes += RunOptFunc (S, &DOptPtrLoad5, 1);
1901     Changes += RunOptFunc (S, &DOptPtrLoad6, 1);
1902     Changes += RunOptFunc (S, &DOptNegAX1, 1);
1903     Changes += RunOptFunc (S, &DOptNegAX2, 1);
1904     Changes += RunOptFunc (S, &DOptNegAX3, 1);
1905     Changes += RunOptFunc (S, &DOptNegAX4, 1);
1906     Changes += RunOptFunc (S, &DOptAdd1, 1);
1907     Changes += RunOptFunc (S, &DOptAdd2, 1);
1908     Changes += RunOptFunc (S, &DOptAdd3, 1);
1909     Changes += RunOptFunc (S, &DOptStore4, 1);
1910     Changes += RunOptFunc (S, &DOptShift1, 1);
1911     Changes += RunOptFunc (S, &DOptShift2, 1);
1912     Changes += RunOptFunc (S, &DOptShift3, 1);
1913     Changes += RunOptFunc (S, &DOptStore1, 1);
1914     Changes += RunOptFunc (S, &DOptStore2, 5);
1915     Changes += RunOptFunc (S, &DOptStore3, 5);
1916
1917     /* Return the number of changes */
1918     return Changes;
1919 }
1920
1921
1922
1923 static unsigned RunOptGroup2 (CodeSeg* S)
1924 /* Run one group of optimization steps. This step involves just decoupling
1925  * instructions by replacing them by instructions that do not depend on
1926  * previous instructions. This makes it easier to find instructions that
1927  * aren't used.
1928  */
1929 {
1930     unsigned Changes = 0;
1931
1932     Changes += RunOptFunc (S, &DOptDecouple, 1);
1933
1934     /* Return the number of changes */
1935     return Changes;
1936 }
1937
1938
1939
1940 static unsigned RunOptGroup3 (CodeSeg* S)
1941 /* Run one group of optimization steps. These steps depend on each other,
1942  * that means that one step may allow another step to do additional work,
1943  * so we will repeat the steps as long as we see any changes.
1944  */
1945 {
1946     unsigned Changes, C;
1947
1948     Changes = 0;
1949     do {
1950         C = 0;
1951
1952         C += RunOptFunc (S, &DOptPtrLoad7, 1);
1953         C += RunOptFunc (S, &DOptNegA1, 1);
1954         C += RunOptFunc (S, &DOptNegA2, 1);
1955         C += RunOptFunc (S, &DOptSub1, 1);
1956         C += RunOptFunc (S, &DOptSub2, 1);
1957         C += RunOptFunc (S, &DOptAdd4, 1);
1958         C += RunOptFunc (S, &DOptAdd5, 1);
1959         C += RunOptFunc (S, &DOptStackOps, 1);
1960         C += RunOptFunc (S, &DOptJumpCascades, 1);
1961         C += RunOptFunc (S, &DOptDeadJumps, 1);
1962         C += RunOptFunc (S, &DOptRTS, 1);
1963         C += RunOptFunc (S, &DOptDeadCode, 1);
1964         C += RunOptFunc (S, &DOptJumpTarget, 1);
1965         C += RunOptFunc (S, &DOptCondBranches, 1);
1966         C += RunOptFunc (S, &DOptRTSJumps1, 1);
1967         C += RunOptFunc (S, &DOptBoolTrans, 1);
1968         C += RunOptFunc (S, &DOptCmp1, 1);
1969         C += RunOptFunc (S, &DOptCmp2, 1);
1970         C += RunOptFunc (S, &DOptCmp3, 1);
1971         C += RunOptFunc (S, &DOptCmp4, 1);
1972         C += RunOptFunc (S, &DOptCmp5, 1);
1973         C += RunOptFunc (S, &DOptCmp6, 1);
1974         C += RunOptFunc (S, &DOptCmp7, 1);
1975         C += RunOptFunc (S, &DOptTest1, 1);
1976         C += RunOptFunc (S, &DOptLoad1, 1);
1977         C += RunOptFunc (S, &DOptUnusedLoads, 1);
1978         C += RunOptFunc (S, &DOptUnusedStores, 1);
1979         C += RunOptFunc (S, &DOptDupLoads, 1);
1980         C += RunOptFunc (S, &DOptStoreLoad, 1);
1981         C += RunOptFunc (S, &DOptTransfers1, 1);
1982         C += RunOptFunc (S, &DOptPushPop, 1);
1983         C += RunOptFunc (S, &DOptPrecalc, 1);
1984
1985         Changes += C;
1986
1987     } while (C);
1988
1989     /* Return the number of changes */
1990     return Changes;
1991 }
1992
1993
1994
1995 static unsigned RunOptGroup4 (CodeSeg* S)
1996 /* 65C02 specific optimizations. */
1997 {
1998     unsigned Changes = 0;
1999
2000     if (CPU >= CPU_65C02) {
2001         Changes += RunOptFunc (S, &DOpt65C02BitOps, 1);
2002         Changes += RunOptFunc (S, &DOpt65C02Ind, 1);
2003         Changes += RunOptFunc (S, &DOpt65C02Stores, 1);
2004         if (Changes) {
2005             /* The 65C02 replacement codes do often make the use of a register
2006              * value unnecessary, so if we have changes, run another load
2007              * removal pass.
2008              */
2009             Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
2010         }
2011     }
2012
2013     /* Return the number of changes */
2014     return Changes;
2015 }
2016
2017
2018
2019 static unsigned RunOptGroup5 (CodeSeg* S)
2020 /* Run another round of pattern replacements. These are done late, since there
2021  * may be better replacements before.
2022  */
2023 {
2024     unsigned Changes = 0;
2025
2026     Changes += RunOptFunc (S, &DOptPush1, 1);
2027     Changes += RunOptFunc (S, &DOptPush2, 1);
2028     Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
2029     Changes += RunOptFunc (S, &DOptTransfers2, 1);
2030
2031     /* Return the number of changes */
2032     return Changes;
2033 }
2034
2035
2036
2037 static unsigned RunOptGroup6 (CodeSeg* S)
2038 /* The last group of optimization steps. Adjust branches, do size optimizations.
2039  */
2040 {
2041     unsigned Changes = 0;
2042     unsigned C;
2043
2044     if (CodeSizeFactor <= 100) {
2045         /* Optimize for size, that is replace operations by shorter ones, even
2046          * if this does hinder further optimizations (no problem since we're
2047          * done soon).
2048          */
2049         C = RunOptFunc (S, &DOptSize1, 1);
2050         if (C) {
2051             Changes += C;
2052             /* Run some optimization passes again, since the size optimizations
2053              * may have opened new oportunities.
2054              */
2055             Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
2056             Changes += RunOptFunc (S, &DOptJumpTarget, 5);
2057         }
2058     }
2059     C = RunOptFunc (S, &DOptSize2, 1);
2060     if (C) {
2061         Changes += C;
2062         /* Run some optimization passes again, since the size optimizations
2063          * may have opened new oportunities.
2064          */
2065         Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
2066         Changes += RunOptFunc (S, &DOptJumpTarget, 5);
2067     }
2068
2069     /* Adjust branch distances */
2070     Changes += RunOptFunc (S, &DOptBranchDist, 3);
2071
2072     /* Replace conditional branches to RTS. If we had changes, we must run dead
2073      * code elimination again, since the change may have introduced dead code.
2074      */
2075     C = RunOptFunc (S, &DOptRTSJumps2, 1);
2076     Changes += C;
2077     if (C) {
2078         Changes += RunOptFunc (S, &DOptDeadCode, 1);
2079     }
2080
2081     /* Return the number of changes */
2082     return Changes;
2083 }
2084
2085
2086
2087 void RunOpt (CodeSeg* S)
2088 /* Run the optimizer */
2089 {
2090     const char* StatFileName;
2091
2092     /* If we shouldn't run the optimizer, bail out */
2093     if (!Optimize) {
2094         return;
2095     }
2096
2097     /* Check if we are requested to write optimizer statistics */
2098     StatFileName = getenv ("CC65_OPTSTATS");
2099     if (StatFileName) {
2100         ReadOptStats (StatFileName);
2101     }
2102
2103     /* Print the name of the function we are working on */
2104     if (S->Func) {
2105         Print (stdout, 1, "Running optimizer for function `%s'\n", S->Func->Name);
2106     } else {
2107         Print (stdout, 1, "Running optimizer for global code segment\n");
2108     }
2109
2110     /* Run groups of optimizations */
2111     RunOptGroup1 (S);
2112     RunOptGroup2 (S);
2113     RunOptGroup3 (S);
2114     RunOptGroup4 (S);
2115     RunOptGroup5 (S);
2116     RunOptGroup6 (S);
2117
2118     /* Write statistics */
2119     if (StatFileName) {
2120         WriteOptStats (StatFileName);
2121     }
2122 }
2123
2124
2125