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