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