]> git.sur5r.net Git - cc65/blob - src/cc65/codeopt.c
More optimizations
[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 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             /* Insert the load from ptr1 */
504             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[3]->LI);
505             CS_InsertEntry (S, X, I+5);
506             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[2]->LI);
507             CS_InsertEntry (S, X, I+6);
508
509             /* Insert the store through ptr1 */
510             X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "ptr1", 0, L[3]->LI);
511             CS_InsertEntry (S, X, I+8+K);
512
513             /* Delete the old code */
514             CS_DelEntry (S, I+9+K);     /* jsr spaspidx */
515             CS_DelEntry (S, I+4);       /* jsr ldauidx */
516             CS_DelEntry (S, I);         /* jsr pushax */
517
518             /* Remember, we had changes */
519             ++Changes;
520
521         }
522
523         /* Next entry */
524         ++I;
525
526     }
527
528     /* Return the number of changes made */
529     return Changes;
530 }
531
532
533
534 /*****************************************************************************/
535 /*                      Optimize loads through pointers                      */
536 /*****************************************************************************/
537
538
539
540 static unsigned OptPtrLoad1 (CodeSeg* S)
541 /* Search for the sequence:
542  *
543  *      clc
544  *      adc     xxx
545  *      tay
546  *      txa
547  *      adc     yyy
548  *      tax
549  *      tya
550  *      ldy
551  *      jsr     ldauidx
552  *
553  * and replace it by:
554  *
555  *      clc
556  *      adc     xxx
557  *      sta     ptr1
558  *      txa
559  *      adc     yyy
560  *      sta     ptr1+1
561  *      ldy
562  *      ldx     #$00
563  *      lda     (ptr1),y
564  */
565 {
566     unsigned Changes = 0;
567
568     /* Walk over the entries */
569     unsigned I = 0;
570     while (I < CS_GetEntryCount (S)) {
571
572         CodeEntry* L[9];
573
574         /* Get next entry */
575         L[0] = CS_GetEntry (S, I);
576
577         /* Check for the sequence */
578         if (L[0]->OPC == OP65_CLC               &&
579             CS_GetEntries (S, L+1, I+1, 8)      &&
580             L[1]->OPC == OP65_ADC               &&
581             L[2]->OPC == OP65_TAY               &&
582             L[3]->OPC == OP65_TXA               &&
583             L[4]->OPC == OP65_ADC               &&
584             L[5]->OPC == OP65_TAX               &&
585             L[6]->OPC == OP65_TYA               &&
586             L[7]->OPC == OP65_LDY               &&
587             CE_IsCallTo (L[8], "ldauidx")       &&
588             !CS_RangeHasLabel (S, I+1, 8)) {
589
590             CodeEntry* X;
591             CodeEntry* P;
592
593             /* Track the insertion point */
594             unsigned IP = I+2;
595
596             /* sta ptr1 */
597             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[2]->LI);
598             CS_InsertEntry (S, X, IP++);
599
600             /* If the instruction before the clc is a ldx, replace the
601              * txa by an lda with the same location of the ldx. Otherwise
602              * transfer the value in X to A.
603              */
604             if ((P = CS_GetPrevEntry (S, I)) != 0 &&
605                 P->OPC == OP65_LDX                &&
606                 !CE_HasLabel (P)) {
607                 X = NewCodeEntry (OP65_LDA, P->AM, P->Arg, 0, P->LI);
608             } else {
609                 X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, L[3]->LI);
610             }
611             CS_InsertEntry (S, X, IP++);
612
613             /* adc yyy */
614             X = NewCodeEntry (OP65_ADC, L[4]->AM, L[4]->Arg, 0, L[4]->LI);
615             CS_InsertEntry (S, X, IP++);
616
617             /* sta ptr1+1 */
618             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1+1", 0, L[5]->LI);
619             CS_InsertEntry (S, X, IP++);
620
621             /* ldy ... */
622             X = NewCodeEntry (OP65_LDY, L[7]->AM, L[7]->Arg, 0, L[7]->LI);
623             CS_InsertEntry (S, X, IP++);
624
625             /* ldx #$00 */
626             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[8]->LI);
627             CS_InsertEntry (S, X, IP++);
628
629             /* lda (ptr1),y */
630             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[8]->LI);
631             CS_InsertEntry (S, X, IP++);
632
633             /* Remove the old instructions */
634             CS_DelEntries (S, IP, 7);
635
636             /* Remember, we had changes */
637             ++Changes;
638
639         }
640
641         /* Next entry */
642         ++I;
643
644     }
645
646     /* Return the number of changes made */
647     return Changes;
648 }
649
650
651
652 static unsigned OptPtrLoad2 (CodeSeg* S)
653 /* Search for the sequence:
654  *
655  *      adc     xxx
656  *      pha
657  *      txa
658  *      iny
659  *      adc     yyy
660  *      tax
661  *      pla
662  *      ldy
663  *      jsr     ldauidx
664  *
665  * and replace it by:
666  *
667  *      adc     xxx
668  *      sta     ptr1
669  *      txa
670  *      iny
671  *      adc     yyy
672  *      sta     ptr1+1
673  *      ldy
674  *      ldx     #$00
675  *      lda     (ptr1),y
676  */
677 {
678     unsigned Changes = 0;
679
680     /* Walk over the entries */
681     unsigned I = 0;
682     while (I < CS_GetEntryCount (S)) {
683
684         CodeEntry* L[9];
685
686         /* Get next entry */
687         L[0] = CS_GetEntry (S, I);
688
689         /* Check for the sequence */
690         if (L[0]->OPC == OP65_ADC               &&
691             CS_GetEntries (S, L+1, I+1, 8)      &&
692             L[1]->OPC == OP65_PHA               &&
693             L[2]->OPC == OP65_TXA               &&
694             L[3]->OPC == OP65_INY               &&
695             L[4]->OPC == OP65_ADC               &&
696             L[5]->OPC == OP65_TAX               &&
697             L[6]->OPC == OP65_PLA               &&
698             L[7]->OPC == OP65_LDY               &&
699             CE_IsCallTo (L[8], "ldauidx")       &&
700             !CS_RangeHasLabel (S, I+1, 8)) {
701
702             CodeEntry* X;
703
704             /* Store the low byte and remove the PHA instead */
705             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI);
706             CS_InsertEntry (S, X, I+1);
707
708             /* Store the high byte */
709             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1+1", 0, L[4]->LI);
710             CS_InsertEntry (S, X, I+6);
711
712             /* Load high and low byte */
713             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[6]->LI);
714             CS_InsertEntry (S, X, I+10);
715             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[6]->LI);
716             CS_InsertEntry (S, X, I+11);
717
718             /* Delete the old code */
719             CS_DelEntry (S, I+12);      /* jsr ldauidx */
720             CS_DelEntry (S, I+8);       /* pla */
721             CS_DelEntry (S, I+7);       /* tax */
722             CS_DelEntry (S, I+2);       /* pha */
723
724             /* Remember, we had changes */
725             ++Changes;
726
727         }
728
729         /* Next entry */
730         ++I;
731
732     }
733
734     /* Return the number of changes made */
735     return Changes;
736 }
737
738
739
740 static unsigned OptPtrLoad3 (CodeSeg* S)
741 /* Search for the sequence:
742  *
743  *      lda     #<(label+0)
744  *      ldx     #>(label+0)
745  *      clc
746  *      adc     xxx
747  *      bcc     L
748  *      inx
749  * L:   ldy     #$00
750  *      jsr     ldauidx
751  *
752  * and replace it by:
753  *
754  *      ldy     xxx
755  *      ldx     #$00
756  *      lda     label,y
757  */
758 {
759     unsigned Changes = 0;
760
761     /* Walk over the entries */
762     unsigned I = 0;
763     while (I < CS_GetEntryCount (S)) {
764
765         CodeEntry* L[8];
766         unsigned Len;
767
768         /* Get next entry */
769         L[0] = CS_GetEntry (S, I);
770
771         /* Check for the sequence */
772         if (L[0]->OPC == OP65_LDA                            &&
773             L[0]->AM == AM65_IMM                             &&
774             CS_GetEntries (S, L+1, I+1, 7)                   &&
775             L[1]->OPC == OP65_LDX                            &&
776             L[1]->AM == AM65_IMM                             &&
777             L[2]->OPC == OP65_CLC                            &&
778             L[3]->OPC == OP65_ADC                            &&
779             (L[3]->AM == AM65_ABS || L[3]->AM == AM65_ZP)    &&
780             (L[4]->OPC == OP65_BCC || L[4]->OPC == OP65_JCC) &&
781             L[4]->JumpTo != 0                                &&
782             L[4]->JumpTo->Owner == L[6]                      &&
783             L[5]->OPC == OP65_INX                            &&
784             L[6]->OPC == OP65_LDY                            &&
785             CE_KnownImm (L[6])                               &&
786             L[6]->Num == 0                                   &&
787             CE_IsCallTo (L[7], "ldauidx")                    &&
788             !CS_RangeHasLabel (S, I+1, 5)                    &&
789             !CE_HasLabel (L[7])                              &&
790             /* Check the label last because this is quite costly */
791             (Len = strlen (L[0]->Arg)) > 3                   &&
792             L[0]->Arg[0] == '<'                              &&
793             L[0]->Arg[1] == '('                              &&
794             strlen (L[1]->Arg) == Len                        &&
795             L[1]->Arg[0] == '>'                              &&
796             memcmp (L[0]->Arg+1, L[1]->Arg+1, Len-1) == 0) {
797
798             CodeEntry* X;
799             char* Label;
800
801             /* We will create all the new stuff behind the current one so
802              * we keep the line references.
803              */
804             X = NewCodeEntry (OP65_LDY, L[3]->AM, L[3]->Arg, 0, L[0]->LI);
805             CS_InsertEntry (S, X, I+8);
806
807             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[0]->LI);
808             CS_InsertEntry (S, X, I+9);
809
810             Label = memcpy (xmalloc (Len-2), L[0]->Arg+2, Len-3);
811             Label[Len-3] = '\0';
812             X = NewCodeEntry (OP65_LDA, AM65_ABSY, Label, 0, L[0]->LI);
813             CS_InsertEntry (S, X, I+10);
814             xfree (Label);
815
816             /* Remove the old code */
817             CS_DelEntries (S, I, 8);
818
819             /* Remember, we had changes */
820             ++Changes;
821
822         }
823
824         /* Next entry */
825         ++I;
826
827     }
828
829     /* Return the number of changes made */
830     return Changes;
831 }
832
833
834
835 static unsigned OptPtrLoad4 (CodeSeg* S)
836 /* Search for the sequence:
837  *
838  *      lda     #<(label+0)
839  *      ldx     #>(label+0)
840  *      ldy     #$xx
841  *      clc
842  *      adc     (sp),y
843  *      bcc     L
844  *      inx
845  * L:   ldy     #$00
846  *      jsr     ldauidx
847  *
848  * and replace it by:
849  *
850  *      ldy     #$xx
851  *      lda     (sp),y
852  *      tay
853  *      ldx     #$00
854  *      lda     label,y
855  */
856 {
857     unsigned Changes = 0;
858
859     /* Walk over the entries */
860     unsigned I = 0;
861     while (I < CS_GetEntryCount (S)) {
862
863         CodeEntry* L[9];
864         unsigned Len;
865
866         /* Get next entry */
867         L[0] = CS_GetEntry (S, I);
868
869         /* Check for the sequence */
870         if (L[0]->OPC == OP65_LDA                            &&
871             L[0]->AM == AM65_IMM                             &&
872             CS_GetEntries (S, L+1, I+1, 8)                   &&
873             L[1]->OPC == OP65_LDX                            &&
874             L[1]->AM == AM65_IMM                             &&
875             !CE_HasLabel (L[1])                              &&
876             L[2]->OPC == OP65_LDY                            &&
877             CE_KnownImm (L[2])                               &&
878             !CE_HasLabel (L[2])                              &&
879             L[3]->OPC == OP65_CLC                            &&
880             !CE_HasLabel (L[3])                              &&
881             L[4]->OPC == OP65_ADC                            &&
882             L[4]->AM == AM65_ZP_INDY                         &&
883             !CE_HasLabel (L[4])                              &&
884             (L[5]->OPC == OP65_BCC || L[5]->OPC == OP65_JCC) &&
885             L[5]->JumpTo != 0                                &&
886             L[5]->JumpTo->Owner == L[7]                      &&
887             !CE_HasLabel (L[5])                              &&
888             L[6]->OPC == OP65_INX                            &&
889             !CE_HasLabel (L[6])                              &&
890             L[7]->OPC == OP65_LDY                            &&
891             CE_KnownImm (L[7])                               &&
892             L[7]->Num == 0                                   &&
893             CE_IsCallTo (L[8], "ldauidx")                    &&
894             !CE_HasLabel (L[8])                              &&
895             /* Check the label last because this is quite costly */
896             (Len = strlen (L[0]->Arg)) > 3                   &&
897             L[0]->Arg[0] == '<'                              &&
898             L[0]->Arg[1] == '('                              &&
899             strlen (L[1]->Arg) == Len                        &&
900             L[1]->Arg[0] == '>'                              &&
901             memcmp (L[0]->Arg+1, L[1]->Arg+1, Len-1) == 0) {
902
903             CodeEntry* X;
904             char* Label;
905
906             /* Add the lda */
907             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[4]->Arg, 0, L[0]->LI);
908             CS_InsertEntry (S, X, I+3);
909
910             /* Add the tay */
911             X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, L[0]->LI);
912             CS_InsertEntry (S, X, I+4);
913
914             /* Add the ldx */
915             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[0]->LI);
916             CS_InsertEntry (S, X, I+5);
917
918             /* Add the lda */
919             Label = memcpy (xmalloc (Len-2), L[0]->Arg+2, Len-3);
920             Label[Len-3] = '\0';
921             X = NewCodeEntry (OP65_LDA, AM65_ABSY, Label, 0, L[0]->LI);
922             CS_InsertEntry (S, X, I+6);
923             xfree (Label);
924
925             /* Remove the old code */
926             CS_DelEntries (S, I, 2);
927             CS_DelEntries (S, I+5, 6);
928
929             /* Remember, we had changes */
930             ++Changes;
931
932         }
933
934         /* Next entry */
935         ++I;
936
937     }
938
939     /* Return the number of changes made */
940     return Changes;
941 }
942
943
944
945 static unsigned OptPtrLoad5 (CodeSeg* S)
946 /* Search for the sequence:
947  *
948  *      lda     zp
949  *      ldx     zp+1
950  *      ldy     xx
951  *      jsr     ldauidx
952  *
953  * and replace it by:
954  *
955  *      ldy     xx
956  *      ldx     #$00
957  *      lda     (zp),y
958  */
959 {
960     unsigned Changes = 0;
961
962     /* Walk over the entries */
963     unsigned I = 0;
964     while (I < CS_GetEntryCount (S)) {
965
966         CodeEntry* L[4];
967         unsigned Len;
968
969         /* Get next entry */
970         L[0] = CS_GetEntry (S, I);
971
972         /* Check for the sequence */
973         if (L[0]->OPC == OP65_LDA && L[0]->AM == AM65_ZP        &&
974             CS_GetEntries (S, L+1, I+1, 3)                      &&
975             !CS_RangeHasLabel (S, I+1, 3)                       &&
976             L[1]->OPC == OP65_LDX && L[1]->AM == AM65_ZP        &&
977             (Len = strlen (L[0]->Arg)) > 0                      &&
978             strncmp (L[0]->Arg, L[1]->Arg, Len) == 0            &&
979             strcmp (L[1]->Arg + Len, "+1") == 0                 &&
980             L[2]->OPC == OP65_LDY                               &&
981             CE_IsCallTo (L[3], "ldauidx")) {
982
983             CodeEntry* X;
984
985             /* ldx #$00 */
986             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[3]->LI);
987             CS_InsertEntry (S, X, I+3);
988
989             /* lda (zp),y */
990             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI);
991             CS_InsertEntry (S, X, I+4);
992
993             /* Remove the old code */
994             CS_DelEntry (S, I+5);
995             CS_DelEntries (S, I, 2);
996
997             /* Remember, we had changes */
998             ++Changes;
999
1000         }
1001
1002         /* Next entry */
1003         ++I;
1004
1005     }
1006
1007     /* Return the number of changes made */
1008     return Changes;
1009 }
1010
1011
1012
1013 static unsigned OptPtrLoad6 (CodeSeg* S)
1014 /* Search for the sequence:
1015  *
1016  *      lda     zp
1017  *      ldx     zp+1
1018  *      ldy     xx
1019  *      jsr     ldaxidx
1020  *
1021  * and replace it by:
1022  *
1023  *      ldy     xx
1024  *      lda     (zp),y
1025  *      tax
1026  *      dey
1027  *      lda     (zp),y
1028  */
1029 {
1030     unsigned Changes = 0;
1031
1032     /* Walk over the entries */
1033     unsigned I = 0;
1034     while (I < CS_GetEntryCount (S)) {
1035
1036         CodeEntry* L[4];
1037         unsigned Len;
1038
1039         /* Get next entry */
1040         L[0] = CS_GetEntry (S, I);
1041
1042         /* Check for the sequence */
1043         if (L[0]->OPC == OP65_LDA && L[0]->AM == AM65_ZP        &&
1044             CS_GetEntries (S, L+1, I+1, 3)                      &&
1045             !CS_RangeHasLabel (S, I+1, 3)                       &&
1046             L[1]->OPC == OP65_LDX && L[1]->AM == AM65_ZP        &&
1047             (Len = strlen (L[0]->Arg)) > 0                      &&
1048             strncmp (L[0]->Arg, L[1]->Arg, Len) == 0            &&
1049             strcmp (L[1]->Arg + Len, "+1") == 0                 &&
1050             L[2]->OPC == OP65_LDY                               &&
1051             CE_IsCallTo (L[3], "ldaxidx")) {
1052
1053             CodeEntry* X;
1054
1055             /* lda (zp),y */
1056             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI);
1057             CS_InsertEntry (S, X, I+4);
1058
1059             /* tax */
1060             X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[3]->LI);
1061             CS_InsertEntry (S, X, I+5);
1062
1063             /* dey */
1064             X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[3]->LI);
1065             CS_InsertEntry (S, X, I+6);
1066
1067             /* lda (zp),y */
1068             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI);
1069             CS_InsertEntry (S, X, I+7);
1070
1071             /* Remove the old code */
1072             CS_DelEntry (S, I+3);
1073             CS_DelEntries (S, I, 2);
1074
1075             /* Remember, we had changes */
1076             ++Changes;
1077
1078         }
1079
1080         /* Next entry */
1081         ++I;
1082
1083     }
1084
1085     /* Return the number of changes made */
1086     return Changes;
1087 }
1088
1089
1090
1091 static unsigned OptPtrLoad7 (CodeSeg* S)
1092 /* Search for the sequence
1093  *
1094  *      ldy     ...
1095  *      jsr     ldauidx
1096  *
1097  * and replace it by:
1098  *
1099  *      ldy     ...
1100  *      stx     ptr1+1
1101  *      sta     ptr1
1102  *      ldx     #$00
1103  *      lda     (ptr1),y
1104  *
1105  * This step must be execute *after* OptPtrLoad1!
1106  */
1107 {
1108     unsigned Changes = 0;
1109
1110     /* Walk over the entries */
1111     unsigned I = 0;
1112     while (I < CS_GetEntryCount (S)) {
1113
1114         CodeEntry* L[2];
1115
1116         /* Get next entry */
1117         L[0] = CS_GetEntry (S, I);
1118
1119         /* Check for the sequence */
1120         if (L[0]->OPC == OP65_LDY               &&
1121             CS_GetEntries (S, L+1, I+1, 1)      &&
1122             CE_IsCallTo (L[1], "ldauidx")       &&
1123             !CE_HasLabel (L[1])) {
1124
1125             CodeEntry* X;
1126
1127             /* Store the high byte */
1128             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI);
1129             CS_InsertEntry (S, X, I+1);
1130
1131             /* Store the low byte */
1132             X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[0]->LI);
1133             CS_InsertEntry (S, X, I+2);
1134
1135             /* Delete the call to ldauidx */
1136             CS_DelEntry (S, I+3);
1137
1138             /* Load the high and low byte */
1139             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[0]->LI);
1140             CS_InsertEntry (S, X, I+3);
1141             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[0]->LI);
1142             CS_InsertEntry (S, X, I+4);
1143
1144             /* Remember, we had changes */
1145             ++Changes;
1146
1147         }
1148
1149         /* Next entry */
1150         ++I;
1151
1152     }
1153
1154     /* Return the number of changes made */
1155     return Changes;
1156 }
1157
1158
1159
1160 /*****************************************************************************/
1161 /*                            Decouple operations                            */
1162 /*****************************************************************************/
1163
1164
1165
1166 static unsigned OptDecouple (CodeSeg* S)
1167 /* Decouple operations, that is, do the following replacements:
1168  *
1169  *   dex        -> ldx #imm
1170  *   inx        -> ldx #imm
1171  *   dey        -> ldy #imm
1172  *   iny        -> ldy #imm
1173  *   tax        -> ldx #imm
1174  *   txa        -> lda #imm
1175  *   tay        -> ldy #imm
1176  *   tya        -> lda #imm
1177  *   lda zp     -> lda #imm
1178  *   ldx zp     -> ldx #imm
1179  *   ldy zp     -> ldy #imm
1180  *
1181  * Provided that the register values are known of course.
1182  */
1183 {
1184     unsigned Changes = 0;
1185     unsigned I;
1186
1187     /* Generate register info for the following step */
1188     CS_GenRegInfo (S);
1189
1190     /* Walk over the entries */
1191     I = 0;
1192     while (I < CS_GetEntryCount (S)) {
1193
1194         const char* Arg;
1195
1196         /* Get next entry and it's input register values */
1197         CodeEntry* E = CS_GetEntry (S, I);
1198         const RegContents* In = &E->RI->In;
1199
1200         /* Assume we have no replacement */
1201         CodeEntry* X = 0;
1202
1203         /* Check the instruction */
1204         switch (E->OPC) {
1205
1206             case OP65_DEX:
1207                 if (E->RI->In.RegX >= 0) {
1208                     Arg = MakeHexArg ((E->RI->In.RegX - 1) & 0xFF);
1209                     X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
1210                 }
1211                 break;
1212
1213             case OP65_DEY:
1214                 if (E->RI->In.RegY >= 0) {
1215                     Arg = MakeHexArg ((E->RI->In.RegY - 1) & 0xFF);
1216                     X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
1217                 }
1218                 break;
1219
1220             case OP65_INX:
1221                 if (E->RI->In.RegX >= 0) {
1222                     Arg = MakeHexArg ((E->RI->In.RegX + 1) & 0xFF);
1223                     X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
1224                 }
1225                 break;
1226
1227             case OP65_INY:
1228                 if (E->RI->In.RegY >= 0) {
1229                     Arg = MakeHexArg ((E->RI->In.RegY + 1) & 0xFF);
1230                     X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
1231                 }
1232                 break;
1233
1234             case OP65_LDA:
1235                 if (E->AM == AM65_ZP) {
1236                     switch (GetKnownReg (E->Use, In)) {
1237                         case REG_TMP1:
1238                             Arg = MakeHexArg (In->Tmp1);
1239                             X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
1240                             break;
1241
1242                         case REG_SREG_LO:
1243                             Arg = MakeHexArg (In->SRegLo);
1244                             X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
1245                             break;
1246
1247                         case REG_SREG_HI:
1248                             Arg = MakeHexArg (In->SRegHi);
1249                             X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
1250                             break;
1251                     }
1252                 }
1253                 break;
1254
1255             case OP65_LDX:
1256                 if (E->AM == AM65_ZP) {
1257                     switch (GetKnownReg (E->Use, In)) {
1258                         case REG_TMP1:
1259                             Arg = MakeHexArg (In->Tmp1);
1260                             X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
1261                             break;
1262
1263                         case REG_SREG_LO:
1264                             Arg = MakeHexArg (In->SRegLo);
1265                             X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
1266                             break;
1267
1268                         case REG_SREG_HI:
1269                             Arg = MakeHexArg (In->SRegHi);
1270                             X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
1271                             break;
1272                     }
1273                 }
1274                 break;
1275
1276             case OP65_LDY:
1277                 if (E->AM == AM65_ZP) {
1278                     switch (GetKnownReg (E->Use, In)) {
1279                         case REG_TMP1:
1280                             Arg = MakeHexArg (In->Tmp1);
1281                             X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
1282                             break;
1283
1284                         case REG_SREG_LO:
1285                             Arg = MakeHexArg (In->SRegLo);
1286                             X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
1287                             break;
1288
1289                         case REG_SREG_HI:
1290                             Arg = MakeHexArg (In->SRegHi);
1291                             X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
1292                             break;
1293                     }
1294                 }
1295                 break;
1296
1297             case OP65_TAX:
1298                 if (E->RI->In.RegA >= 0) {
1299                     Arg = MakeHexArg (In->RegA);
1300                     X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
1301                 }
1302                 break;
1303
1304             case OP65_TAY:
1305                 if (E->RI->In.RegA >= 0) {
1306                     Arg = MakeHexArg (In->RegA);
1307                     X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
1308                 }
1309                 break;
1310
1311             case OP65_TXA:
1312                 if (E->RI->In.RegX >= 0) {
1313                     Arg = MakeHexArg (In->RegX);
1314                     X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
1315                 }
1316                 break;
1317
1318             case OP65_TYA:
1319                 if (E->RI->In.RegY >= 0) {
1320                     Arg = MakeHexArg (In->RegY);
1321                     X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
1322                 }
1323                 break;
1324
1325             default:
1326                 /* Avoid gcc warnings */
1327                 break;
1328
1329         }
1330
1331         /* Insert the replacement if we have one */
1332         if (X) {
1333             CS_InsertEntry (S, X, I+1);
1334             CS_DelEntry (S, I);
1335             ++Changes;
1336         }
1337
1338         /* Next entry */
1339         ++I;
1340
1341     }
1342
1343     /* Free register info */
1344     CS_FreeRegInfo (S);
1345
1346     /* Return the number of changes made */
1347     return Changes;
1348 }
1349
1350
1351
1352 /*****************************************************************************/
1353 /*                              struct OptFunc                               */
1354 /*****************************************************************************/
1355
1356
1357
1358 typedef struct OptFunc OptFunc;
1359 struct OptFunc {
1360     unsigned       (*Func) (CodeSeg*);  /* Optimizer function */
1361     const char*    Name;                /* Name of the function/group */
1362     unsigned       CodeSizeFactor;      /* Code size factor for this opt func */
1363     unsigned long  TotalRuns;           /* Total number of runs */
1364     unsigned long  LastRuns;            /* Last number of runs */
1365     unsigned long  TotalChanges;        /* Total number of changes */
1366     unsigned long  LastChanges;         /* Last number of changes */
1367     char           Disabled;            /* True if function disabled */
1368 };
1369
1370
1371
1372 /*****************************************************************************/
1373 /*                                   Code                                    */
1374 /*****************************************************************************/
1375
1376
1377
1378 /* A list of all the function descriptions */
1379 static OptFunc DOpt65C02BitOps  = { Opt65C02BitOps,  "Opt65C02BitOps",   66, 0, 0, 0, 0, 0 };
1380 static OptFunc DOpt65C02Ind     = { Opt65C02Ind,     "Opt65C02Ind",     100, 0, 0, 0, 0, 0 };
1381 static OptFunc DOpt65C02Stores  = { Opt65C02Stores,  "Opt65C02Stores",  100, 0, 0, 0, 0, 0 };
1382 static OptFunc DOptAdd1         = { OptAdd1,         "OptAdd1",         125, 0, 0, 0, 0, 0 };
1383 static OptFunc DOptAdd2         = { OptAdd2,         "OptAdd2",         200, 0, 0, 0, 0, 0 };
1384 static OptFunc DOptAdd3         = { OptAdd3,         "OptAdd3",          90, 0, 0, 0, 0, 0 };
1385 static OptFunc DOptAdd4         = { OptAdd4,         "OptAdd4",         100, 0, 0, 0, 0, 0 };
1386 static OptFunc DOptAdd5         = { OptAdd5,         "OptAdd5",          40, 0, 0, 0, 0, 0 };
1387 static OptFunc DOptBoolTrans    = { OptBoolTrans,    "OptBoolTrans",    100, 0, 0, 0, 0, 0 };
1388 static OptFunc DOptBranchDist   = { OptBranchDist,   "OptBranchDist",     0, 0, 0, 0, 0, 0 };
1389 static OptFunc DOptCmp1         = { OptCmp1,         "OptCmp1",          85, 0, 0, 0, 0, 0 };
1390 static OptFunc DOptCmp2         = { OptCmp2,         "OptCmp2",          75, 0, 0, 0, 0, 0 };
1391 static OptFunc DOptCmp3         = { OptCmp3,         "OptCmp3",          75, 0, 0, 0, 0, 0 };
1392 static OptFunc DOptCmp4         = { OptCmp4,         "OptCmp4",         100, 0, 0, 0, 0, 0 };
1393 static OptFunc DOptCmp5         = { OptCmp5,         "OptCmp5",         100, 0, 0, 0, 0, 0 };
1394 static OptFunc DOptCmp6         = { OptCmp6,         "OptCmp6",          85, 0, 0, 0, 0, 0 };
1395 static OptFunc DOptCmp7         = { OptCmp7,         "OptCmp7",          50, 0, 0, 0, 0, 0 };
1396 static OptFunc DOptCondBranches = { OptCondBranches, "OptCondBranches",  80, 0, 0, 0, 0, 0 };
1397 static OptFunc DOptDeadCode     = { OptDeadCode,     "OptDeadCode",     100, 0, 0, 0, 0, 0 };
1398 static OptFunc DOptDeadJumps    = { OptDeadJumps,    "OptDeadJumps",    100, 0, 0, 0, 0, 0 };
1399 static OptFunc DOptDecouple     = { OptDecouple,     "OptDecouple",     100, 0, 0, 0, 0, 0 };
1400 static OptFunc DOptDupLoads     = { OptDupLoads,     "OptDupLoads",       0, 0, 0, 0, 0, 0 };
1401 static OptFunc DOptJumpCascades = { OptJumpCascades, "OptJumpCascades", 100, 0, 0, 0, 0, 0 };
1402 static OptFunc DOptJumpTarget   = { OptJumpTarget,   "OptJumpTarget",   100, 0, 0, 0, 0, 0 };
1403 static OptFunc DOptLoad1        = { OptLoad1,        "OptLoad1",        100, 0, 0, 0, 0, 0 };
1404 static OptFunc DOptRTS          = { OptRTS,          "OptRTS",          100, 0, 0, 0, 0, 0 };
1405 static OptFunc DOptRTSJumps1    = { OptRTSJumps1,    "OptRTSJumps1",    100, 0, 0, 0, 0, 0 };
1406 static OptFunc DOptRTSJumps2    = { OptRTSJumps2,    "OptRTSJumps2",    100, 0, 0, 0, 0, 0 };
1407 static OptFunc DOptNegA1        = { OptNegA1,        "OptNegA1",        100, 0, 0, 0, 0, 0 };
1408 static OptFunc DOptNegA2        = { OptNegA2,        "OptNegA2",        100, 0, 0, 0, 0, 0 };
1409 static OptFunc DOptNegAX1       = { OptNegAX1,       "OptNegAX1",       100, 0, 0, 0, 0, 0 };
1410 static OptFunc DOptNegAX2       = { OptNegAX2,       "OptNegAX2",       100, 0, 0, 0, 0, 0 };
1411 static OptFunc DOptNegAX3       = { OptNegAX3,       "OptNegAX3",       100, 0, 0, 0, 0, 0 };
1412 static OptFunc DOptNegAX4       = { OptNegAX4,       "OptNegAX4",       100, 0, 0, 0, 0, 0 };
1413 static OptFunc DOptPtrLoad1     = { OptPtrLoad1,     "OptPtrLoad1",     100, 0, 0, 0, 0, 0 };
1414 static OptFunc DOptPtrLoad2     = { OptPtrLoad2,     "OptPtrLoad2",     100, 0, 0, 0, 0, 0 };
1415 static OptFunc DOptPtrLoad3     = { OptPtrLoad3,     "OptPtrLoad3",     100, 0, 0, 0, 0, 0 };
1416 static OptFunc DOptPtrLoad4     = { OptPtrLoad4,     "OptPtrLoad4",     100, 0, 0, 0, 0, 0 };
1417 static OptFunc DOptPtrLoad5     = { OptPtrLoad5,     "OptPtrLoad5",      65, 0, 0, 0, 0, 0 };
1418 static OptFunc DOptPtrLoad6     = { OptPtrLoad6,     "OptPtrLoad6",      86, 0, 0, 0, 0, 0 };
1419 static OptFunc DOptPtrLoad7     = { OptPtrLoad7,     "OptPtrLoad7",     100, 0, 0, 0, 0, 0 };
1420 static OptFunc DOptPtrStore1    = { OptPtrStore1,    "OptPtrStore1",    100, 0, 0, 0, 0, 0 };
1421 static OptFunc DOptPush1        = { OptPush1,        "OptPush1",         65, 0, 0, 0, 0, 0 };
1422 static OptFunc DOptPush2        = { OptPush2,        "OptPush2",         50, 0, 0, 0, 0, 0 };
1423 static OptFunc DOptPushPop      = { OptPushPop,      "OptPushPop",        0, 0, 0, 0, 0, 0 };
1424 static OptFunc DOptShift1       = { OptShift1,       "OptShift1",       100, 0, 0, 0, 0, 0 };
1425 static OptFunc DOptShift2       = { OptShift2,       "OptShift2",       100, 0, 0, 0, 0, 0 };
1426 static OptFunc DOptShift3       = { OptShift3,       "OptShift3",       110, 0, 0, 0, 0, 0 };
1427 static OptFunc DOptSize1        = { OptSize1,        "OptSize1",        100, 0, 0, 0, 0, 0 };
1428 static OptFunc DOptSize2        = { OptSize2,        "OptSize2",        100, 0, 0, 0, 0, 0 };
1429 static OptFunc DOptStackOps     = { OptStackOps,     "OptStackOps",     100, 0, 0, 0, 0, 0 };
1430 static OptFunc DOptStore1       = { OptStore1,       "OptStore1",        70, 0, 0, 0, 0, 0 };
1431 static OptFunc DOptStore2       = { OptStore2,       "OptStore2",       220, 0, 0, 0, 0, 0 };
1432 static OptFunc DOptStore3       = { OptStore3,       "OptStore3",       120, 0, 0, 0, 0, 0 };
1433 static OptFunc DOptStore4       = { OptStore4,       "OptStore4",        50, 0, 0, 0, 0, 0 };
1434 static OptFunc DOptStoreLoad    = { OptStoreLoad,    "OptStoreLoad",      0, 0, 0, 0, 0, 0 };
1435 static OptFunc DOptSub1         = { OptSub1,         "OptSub1",         100, 0, 0, 0, 0, 0 };
1436 static OptFunc DOptSub2         = { OptSub2,         "OptSub2",         100, 0, 0, 0, 0, 0 };
1437 static OptFunc DOptTest1        = { OptTest1,        "OptTest1",        100, 0, 0, 0, 0, 0 };
1438 static OptFunc DOptTransfers    = { OptTransfers,    "OptTransfers",      0, 0, 0, 0, 0, 0 };
1439 static OptFunc DOptUnusedLoads  = { OptUnusedLoads,  "OptUnusedLoads",    0, 0, 0, 0, 0, 0 };
1440 static OptFunc DOptUnusedStores = { OptUnusedStores, "OptUnusedStores",   0, 0, 0, 0, 0, 0 };
1441
1442
1443 /* Table containing all the steps in alphabetical order */
1444 static OptFunc* OptFuncs[] = {
1445     &DOpt65C02BitOps,
1446     &DOpt65C02Ind,
1447     &DOpt65C02Stores,
1448     &DOptAdd1,
1449     &DOptAdd2,
1450     &DOptAdd3,
1451     &DOptAdd4,
1452     &DOptAdd5,
1453     &DOptBoolTrans,
1454     &DOptBranchDist,
1455     &DOptCmp1,
1456     &DOptCmp2,
1457     &DOptCmp3,
1458     &DOptCmp4,
1459     &DOptCmp5,
1460     &DOptCmp6,
1461     &DOptCmp7,
1462     &DOptCondBranches,
1463     &DOptDeadCode,
1464     &DOptDeadJumps,
1465     &DOptDecouple,
1466     &DOptDupLoads,
1467     &DOptJumpCascades,
1468     &DOptJumpTarget,
1469     &DOptLoad1,
1470     &DOptNegA1,
1471     &DOptNegA2,
1472     &DOptNegAX1,
1473     &DOptNegAX2,
1474     &DOptNegAX3,
1475     &DOptNegAX4,
1476     &DOptPtrLoad1,
1477     &DOptPtrLoad2,
1478     &DOptPtrLoad3,
1479     &DOptPtrLoad4,
1480     &DOptPtrLoad5,
1481     &DOptPtrLoad6,
1482     &DOptPtrLoad7,
1483     &DOptPtrStore1,
1484     &DOptPush1,
1485     &DOptPush2,
1486     &DOptPushPop,
1487     &DOptRTS,
1488     &DOptRTSJumps1,
1489     &DOptRTSJumps2,
1490     &DOptShift1,
1491     &DOptShift2,
1492     &DOptShift3,
1493     &DOptSize1,
1494     &DOptSize2,
1495     &DOptStackOps,
1496     &DOptStore1,
1497     &DOptStore2,
1498     &DOptStore3,
1499     &DOptStore4,
1500     &DOptStoreLoad,
1501     &DOptSub1,
1502     &DOptSub2,
1503     &DOptTest1,
1504     &DOptTransfers,
1505     &DOptUnusedLoads,
1506     &DOptUnusedStores,
1507 };
1508 #define OPTFUNC_COUNT  (sizeof(OptFuncs) / sizeof(OptFuncs[0]))
1509
1510
1511
1512 static int CmpOptStep (const void* Key, const void* Func)
1513 /* Compare function for bsearch */
1514 {
1515     return strcmp (Key, (*(const OptFunc**)Func)->Name);
1516 }
1517
1518
1519
1520 static OptFunc* FindOptFunc (const char* Name)
1521 /* Find an optimizer step by name in the table and return a pointer. Return
1522  * NULL if no such step is found.
1523  */
1524 {
1525     /* Search for the function in the list */
1526     OptFunc** O = bsearch (Name, OptFuncs, OPTFUNC_COUNT, sizeof (OptFuncs[0]), CmpOptStep);
1527     return O? *O : 0;
1528 }
1529
1530
1531
1532 static OptFunc* GetOptFunc (const char* Name)
1533 /* Find an optimizer step by name in the table and return a pointer. Print an
1534  * error and call AbEnd if not found.
1535  */
1536 {
1537     /* Search for the function in the list */
1538     OptFunc* F = FindOptFunc (Name);
1539     if (F == 0) {
1540         /* Not found */
1541         AbEnd ("Optimization step `%s' not found", Name);
1542     }
1543     return F;
1544 }
1545
1546
1547
1548 void DisableOpt (const char* Name)
1549 /* Disable the optimization with the given name */
1550 {
1551     if (strcmp (Name, "any") == 0) {
1552         unsigned I;
1553         for (I = 0; I < OPTFUNC_COUNT; ++I) {
1554             OptFuncs[I]->Disabled = 1;
1555         }
1556     } else {
1557         GetOptFunc(Name)->Disabled = 1;
1558     }
1559 }
1560
1561
1562
1563 void EnableOpt (const char* Name)
1564 /* Enable the optimization with the given name */
1565 {
1566     if (strcmp (Name, "any") == 0) {
1567         unsigned I;
1568         for (I = 0; I < OPTFUNC_COUNT; ++I) {
1569             OptFuncs[I]->Disabled = 0;
1570         }
1571     } else {
1572         GetOptFunc(Name)->Disabled = 0;
1573     }
1574 }
1575
1576
1577
1578 void ListOptSteps (FILE* F)
1579 /* List all optimization steps */
1580 {
1581     unsigned I;
1582     for (I = 0; I < OPTFUNC_COUNT; ++I) {
1583         fprintf (F, "%s\n", OptFuncs[I]->Name);
1584     }
1585 }
1586
1587
1588
1589 static void ReadOptStats (const char* Name)
1590 /* Read the optimizer statistics file */
1591 {
1592     char Buf [256];
1593     unsigned Lines;
1594
1595     /* Try to open the file */
1596     FILE* F = fopen (Name, "r");
1597     if (F == 0) {
1598         /* Ignore the error */
1599         return;
1600     }
1601
1602     /* Read and parse the lines */
1603     Lines = 0;
1604     while (fgets (Buf, sizeof (Buf), F) != 0) {
1605
1606         char* B;
1607         unsigned Len;
1608         OptFunc* Func;
1609
1610         /* Fields */
1611         char Name[32];
1612         unsigned long  TotalRuns;
1613         unsigned long  TotalChanges;
1614
1615         /* Count lines */
1616         ++Lines;
1617
1618         /* Remove trailing white space including the line terminator */
1619         B = Buf;
1620         Len = strlen (B);
1621         while (Len > 0 && IsSpace (B[Len-1])) {
1622             --Len;
1623         }
1624         B[Len] = '\0';
1625
1626         /* Remove leading whitespace */
1627         while (IsSpace (*B)) {
1628             ++B;
1629         }
1630
1631         /* Check for empty and comment lines */
1632         if (*B == '\0' || *B == ';' || *B == '#') {
1633             continue;
1634         }
1635
1636         /* Parse the line */
1637         if (sscanf (B, "%31s %lu %*u %lu %*u", Name, &TotalRuns, &TotalChanges) != 3) {
1638             /* Syntax error */
1639             continue;
1640         }
1641
1642         /* Search for the optimizer step. */
1643         Func = FindOptFunc (Name);
1644         if (Func == 0) {
1645             /* Not found */
1646             continue;
1647         }
1648
1649         /* Found the step, set the fields */
1650         Func->TotalRuns    = TotalRuns;
1651         Func->TotalChanges = TotalChanges;
1652
1653     }
1654
1655     /* Close the file, ignore errors here. */
1656     fclose (F);
1657 }
1658
1659
1660
1661 static void WriteOptStats (const char* Name)
1662 /* Write the optimizer statistics file */
1663 {
1664     unsigned I;
1665
1666     /* Try to open the file */
1667     FILE* F = fopen (Name, "w");
1668     if (F == 0) {
1669         /* Ignore the error */
1670         return;
1671     }
1672
1673     /* Write a header */
1674     fprintf (F,
1675              "; Optimizer           Total  Last   Total  Last\n"
1676              ";   Step              Runs   Runs    Chg   Chg\n");
1677
1678
1679     /* Write the data */
1680     for (I = 0; I < OPTFUNC_COUNT; ++I) {
1681         const OptFunc* O = OptFuncs[I];
1682         fprintf (F,
1683                  "%-20s %6lu %6lu %6lu %6lu\n",
1684                  O->Name,
1685                  O->TotalRuns,
1686                  O->LastRuns,
1687                  O->TotalChanges,
1688                  O->LastChanges);
1689     }
1690
1691     /* Close the file, ignore errors here. */
1692     fclose (F);
1693 }
1694
1695
1696
1697 static unsigned RunOptFunc (CodeSeg* S, OptFunc* F, unsigned Max)
1698 /* Run one optimizer function Max times or until there are no more changes */
1699 {
1700     unsigned Changes, C;
1701
1702     /* Don't run the function if it is disabled or if it is prohibited by the
1703      * code size factor
1704      */
1705     if (F->Disabled || F->CodeSizeFactor > CodeSizeFactor) {
1706         return 0;
1707     }
1708
1709     /* Run this until there are no more changes */
1710     Changes = 0;
1711     do {
1712
1713         /* Run the function */
1714         C = F->Func (S);
1715         Changes += C;
1716
1717         /* Do statistics */
1718         ++F->TotalRuns;
1719         ++F->LastRuns;
1720         F->TotalChanges += C;
1721         F->LastChanges  += C;
1722
1723     } while (--Max && C > 0);
1724
1725     /* Return the number of changes */
1726     return Changes;
1727 }
1728
1729
1730
1731 static unsigned RunOptGroup1 (CodeSeg* S)
1732 /* Run the first group of optimization steps. These steps translate known
1733  * patterns emitted by the code generator into more optimal patterns. Order
1734  * of the steps is important, because some of the steps done earlier cover
1735  * the same patterns as later steps as subpatterns.
1736  */
1737 {
1738     unsigned Changes = 0;
1739
1740     Changes += RunOptFunc (S, &DOptPtrStore1, 1);
1741     Changes += RunOptFunc (S, &DOptPtrLoad1, 1);
1742     Changes += RunOptFunc (S, &DOptPtrLoad2, 1);
1743     Changes += RunOptFunc (S, &DOptPtrLoad3, 1);
1744     Changes += RunOptFunc (S, &DOptPtrLoad4, 1);
1745     Changes += RunOptFunc (S, &DOptPtrLoad5, 1);
1746     Changes += RunOptFunc (S, &DOptPtrLoad6, 1);
1747     Changes += RunOptFunc (S, &DOptNegAX1, 1);
1748     Changes += RunOptFunc (S, &DOptNegAX2, 1);
1749     Changes += RunOptFunc (S, &DOptNegAX3, 1);
1750     Changes += RunOptFunc (S, &DOptNegAX4, 1);
1751     Changes += RunOptFunc (S, &DOptAdd1, 1);
1752     Changes += RunOptFunc (S, &DOptAdd2, 1);
1753     Changes += RunOptFunc (S, &DOptAdd3, 1);
1754     Changes += RunOptFunc (S, &DOptShift1, 1);
1755     Changes += RunOptFunc (S, &DOptShift2, 1);
1756     Changes += RunOptFunc (S, &DOptShift3, 1);
1757     Changes += RunOptFunc (S, &DOptStore1, 1);
1758     Changes += RunOptFunc (S, &DOptStore2, 5);
1759     Changes += RunOptFunc (S, &DOptStore3, 5);
1760     Changes += RunOptFunc (S, &DOptStore4, 1);
1761
1762     /* Return the number of changes */
1763     return Changes;
1764 }
1765
1766
1767
1768 static unsigned RunOptGroup2 (CodeSeg* S)
1769 /* Run one group of optimization steps. This step involves just decoupling
1770  * instructions by replacing them by instructions that do not depend on
1771  * previous instructions. This makes it easier to find instructions that
1772  * aren't used.
1773  */
1774 {
1775     unsigned Changes = 0;
1776
1777     Changes += RunOptFunc (S, &DOptDecouple, 1);
1778
1779     /* Return the number of changes */
1780     return Changes;
1781 }
1782
1783
1784
1785 static unsigned RunOptGroup3 (CodeSeg* S)
1786 /* Run one group of optimization steps. These steps depend on each other,
1787  * that means that one step may allow another step to do additional work,
1788  * so we will repeat the steps as long as we see any changes.
1789  */
1790 {
1791     unsigned Changes, C;
1792
1793     Changes = 0;
1794     do {
1795         C = 0;
1796
1797         C += RunOptFunc (S, &DOptPtrLoad7, 1);
1798         C += RunOptFunc (S, &DOptNegA1, 1);
1799         C += RunOptFunc (S, &DOptNegA2, 1);
1800         C += RunOptFunc (S, &DOptSub1, 1);
1801         C += RunOptFunc (S, &DOptSub2, 1);
1802         C += RunOptFunc (S, &DOptAdd4, 1);
1803         C += RunOptFunc (S, &DOptAdd5, 1);
1804         C += RunOptFunc (S, &DOptStackOps, 1);
1805         C += RunOptFunc (S, &DOptJumpCascades, 1);
1806         C += RunOptFunc (S, &DOptDeadJumps, 1);
1807         C += RunOptFunc (S, &DOptRTS, 1);
1808         C += RunOptFunc (S, &DOptDeadCode, 1);
1809         C += RunOptFunc (S, &DOptJumpTarget, 1);
1810         C += RunOptFunc (S, &DOptCondBranches, 1);
1811         C += RunOptFunc (S, &DOptRTSJumps1, 1);
1812         C += RunOptFunc (S, &DOptBoolTrans, 1);
1813         C += RunOptFunc (S, &DOptCmp1, 1);
1814         C += RunOptFunc (S, &DOptCmp2, 1);
1815         C += RunOptFunc (S, &DOptCmp3, 1);
1816         C += RunOptFunc (S, &DOptCmp4, 1);
1817         C += RunOptFunc (S, &DOptCmp5, 1);
1818         C += RunOptFunc (S, &DOptCmp6, 1);
1819         C += RunOptFunc (S, &DOptCmp7, 1);
1820         C += RunOptFunc (S, &DOptTest1, 1);
1821         C += RunOptFunc (S, &DOptLoad1, 1);
1822         C += RunOptFunc (S, &DOptUnusedLoads, 1);
1823         C += RunOptFunc (S, &DOptUnusedStores, 1);
1824         C += RunOptFunc (S, &DOptDupLoads, 1);
1825         C += RunOptFunc (S, &DOptStoreLoad, 1);
1826         C += RunOptFunc (S, &DOptTransfers, 1);
1827         C += RunOptFunc (S, &DOptPushPop, 1);
1828
1829         Changes += C;
1830
1831     } while (C);
1832
1833     /* Return the number of changes */
1834     return Changes;
1835 }
1836
1837
1838
1839 static unsigned RunOptGroup4 (CodeSeg* S)
1840 /* 65C02 specific optimizations. */
1841 {
1842     unsigned Changes = 0;
1843
1844     if (CPU >= CPU_65C02) {
1845         Changes += RunOptFunc (S, &DOpt65C02BitOps, 1);
1846         Changes += RunOptFunc (S, &DOpt65C02Ind, 1);
1847         Changes += RunOptFunc (S, &DOpt65C02Stores, 1);
1848         if (Changes) {
1849             /* The 65C02 replacement codes do often make the use of a register
1850              * value unnecessary, so if we have changes, run another load
1851              * removal pass.
1852              */
1853             Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
1854         }
1855     }
1856
1857     /* Return the number of changes */
1858     return Changes;
1859 }
1860
1861
1862
1863 static unsigned RunOptGroup5 (CodeSeg* S)
1864 /* Run another round of pattern replacements. These are done late, since there
1865  * may be better replacements before.
1866  */
1867 {
1868     unsigned Changes = 0;
1869
1870     Changes += RunOptFunc (S, &DOptPush1, 1);
1871     Changes += RunOptFunc (S, &DOptPush2, 1);
1872     Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
1873
1874     /* Return the number of changes */
1875     return Changes;
1876 }
1877
1878
1879
1880 static unsigned RunOptGroup6 (CodeSeg* S)
1881 /* The last group of optimization steps. Adjust branches, do size optimizations.
1882  */
1883 {
1884     unsigned Changes = 0;
1885     unsigned C;
1886
1887     if (CodeSizeFactor <= 100) {
1888         /* Optimize for size, that is replace operations by shorter ones, even
1889          * if this does hinder further optimizations (no problem since we're
1890          * done soon).
1891          */
1892         C = RunOptFunc (S, &DOptSize1, 1);
1893         if (C) {
1894             Changes += C;
1895             /* Run some optimization passes again, since the size optimizations
1896              * may have opened new oportunities.
1897              */
1898             Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
1899             Changes += RunOptFunc (S, &DOptJumpTarget, 5);
1900         }
1901     }
1902     C = RunOptFunc (S, &DOptSize2, 1);
1903     if (C) {
1904         Changes += C;
1905         /* Run some optimization passes again, since the size optimizations
1906          * may have opened new oportunities.
1907          */
1908         Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
1909         Changes += RunOptFunc (S, &DOptJumpTarget, 5);
1910     }
1911
1912     /* Adjust branch distances */
1913     Changes += RunOptFunc (S, &DOptBranchDist, 3);
1914
1915     /* Replace conditional branches to RTS. If we had changes, we must run dead
1916      * code elimination again, since the change may have introduced dead code.
1917      */
1918     C = RunOptFunc (S, &DOptRTSJumps2, 1);
1919     Changes += C;
1920     if (C) {
1921         Changes += RunOptFunc (S, &DOptDeadCode, 1);
1922     }
1923
1924     /* Return the number of changes */
1925     return Changes;
1926 }
1927
1928
1929
1930 void RunOpt (CodeSeg* S)
1931 /* Run the optimizer */
1932 {
1933     const char* StatFileName;
1934
1935     /* If we shouldn't run the optimizer, bail out */
1936     if (!Optimize) {
1937         return;
1938     }
1939
1940     /* Check if we are requested to write optimizer statistics */
1941     StatFileName = getenv ("CC65_OPTSTATS");
1942     if (StatFileName) {
1943         ReadOptStats (StatFileName);
1944     }
1945
1946     /* Print the name of the function we are working on */
1947     if (S->Func) {
1948         Print (stdout, 1, "Running optimizer for function `%s'\n", S->Func->Name);
1949     } else {
1950         Print (stdout, 1, "Running optimizer for global code segment\n");
1951     }
1952
1953     /* Run groups of optimizations */
1954     RunOptGroup1 (S);
1955     RunOptGroup2 (S);
1956     RunOptGroup3 (S);
1957     RunOptGroup4 (S);
1958     RunOptGroup5 (S);
1959     RunOptGroup6 (S);
1960
1961     /* Write statistics */
1962     if (StatFileName) {
1963         WriteOptStats (StatFileName);
1964     }
1965 }
1966
1967
1968