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