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