]> git.sur5r.net Git - cc65/blob - src/cc65/codeopt.c
More shift optimizations.
[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 "coptshift.h"
61 #include "coptsize.h"
62 #include "coptstop.h"
63 #include "coptstore.h"
64 #include "coptsub.h"
65 #include "copttest.h"
66 #include "error.h"
67 #include "global.h"
68 #include "codeopt.h"
69
70
71
72 /*****************************************************************************/
73 /*                              Optimize loads                               */
74 /*****************************************************************************/
75
76
77
78 static unsigned OptLoad1 (CodeSeg* S)
79 /* Search for a call to ldaxysp where X is not used later and replace it by
80  * a load of just the A register.
81  */
82 {
83     unsigned I;
84     unsigned Changes = 0;
85
86     /* Walk over the entries */
87     I = 0;
88     while (I < CS_GetEntryCount (S)) {
89
90         CodeEntry* E;
91
92         /* Get next entry */
93         E = CS_GetEntry (S, I);
94
95         /* Check for the sequence */
96         if (CE_IsCallTo (E, "ldaxysp")          &&
97             RegValIsKnown (E->RI->In.RegY)      &&
98             !RegXUsed (S, I+1)) {
99
100             CodeEntry* X;
101
102             /* Reload the Y register */
103             const char* Arg = MakeHexArg (E->RI->In.RegY - 1);
104             X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
105             CS_InsertEntry (S, X, I+1);
106
107             /* Load from stack */
108             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, E->LI);
109             CS_InsertEntry (S, X, I+2);
110
111             /* Now remove the call to the subroutine */
112             CS_DelEntry (S, I);
113
114             /* Remember, we had changes */
115             ++Changes;
116
117         }
118
119         /* Next entry */
120         ++I;
121
122     }
123
124     /* Return the number of changes made */
125     return Changes;
126 }
127
128
129
130 static unsigned OptLoad2 (CodeSeg* S)
131 /* Replace calls to ldaxysp by inline code */
132 {
133     unsigned I;
134     unsigned Changes = 0;
135
136     /* Walk over the entries */
137     I = 0;
138     while (I < CS_GetEntryCount (S)) {
139
140         CodeEntry* L[3];
141
142         /* Get next entry */
143         L[0] = CS_GetEntry (S, I);
144
145         /* Check for the sequence */
146         if (CE_IsCallTo (L[0], "ldaxysp")) {
147
148             CodeEntry* X;
149
150             /* Followed by sta abs/stx abs? */
151             if (CS_GetEntries (S, L+1, I+1, 2)                  &&
152                 L[1]->OPC == OP65_STA                           &&
153                 L[2]->OPC == OP65_STX                           &&
154                 (L[1]->Arg == 0                         ||
155                  L[2]->Arg == 0                         ||
156                  strcmp (L[1]->Arg, L[2]->Arg) != 0)            &&
157                 !CS_RangeHasLabel (S, I+1, 2)                   &&
158                 !RegXUsed (S, I+3)) {
159
160                 /* A/X are stored into memory somewhere and X is not used
161                  * later
162                  */
163
164                 /* lda (sp),y */
165                 X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[0]->LI);
166                 CS_InsertEntry (S, X, I+3);
167
168                 /* sta abs */
169                 X = NewCodeEntry (OP65_STA, L[2]->AM, L[2]->Arg, 0, L[2]->LI);
170                 CS_InsertEntry (S, X, I+4);
171
172                 /* dey */
173                 X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[0]->LI);
174                 CS_InsertEntry (S, X, I+5);
175
176                 /* lda (sp),y */
177                 X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[0]->LI);
178                 CS_InsertEntry (S, X, I+6);
179
180                 /* sta abs */
181                 X = NewCodeEntry (OP65_STA, L[1]->AM, L[1]->Arg, 0, L[1]->LI);
182                 CS_InsertEntry (S, X, I+7);
183
184                 /* Now remove the call to the subroutine and the sta/stx */
185                 CS_DelEntries (S, I, 3);
186
187             } else {
188
189                 /* Standard replacement */
190
191                 /* lda (sp),y */
192                 X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[0]->LI);
193                 CS_InsertEntry (S, X, I+1);
194
195                 /* tax */
196                 X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[0]->LI);
197                 CS_InsertEntry (S, X, I+2);
198
199                 /* dey */
200                 X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[0]->LI);
201                 CS_InsertEntry (S, X, I+3);
202
203                 /* lda (sp),y */
204                 X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[0]->LI);
205                 CS_InsertEntry (S, X, I+4);
206
207                 /* Now remove the call to the subroutine */
208                 CS_DelEntry (S, I);
209
210             }
211
212             /* Remember, we had changes */
213             ++Changes;
214
215         }
216
217         /* Next entry */
218         ++I;
219     }
220
221     /* Return the number of changes made */
222     return Changes;
223 }
224
225
226
227 /*****************************************************************************/
228 /*                            Decouple operations                            */
229 /*****************************************************************************/
230
231
232
233 static unsigned OptDecouple (CodeSeg* S)
234 /* Decouple operations, that is, do the following replacements:
235  *
236  *   dex        -> ldx #imm
237  *   inx        -> ldx #imm
238  *   dey        -> ldy #imm
239  *   iny        -> ldy #imm
240  *   tax        -> ldx #imm
241  *   txa        -> lda #imm
242  *   tay        -> ldy #imm
243  *   tya        -> lda #imm
244  *   lda zp     -> lda #imm
245  *   ldx zp     -> ldx #imm
246  *   ldy zp     -> ldy #imm
247  *
248  * Provided that the register values are known of course.
249  */
250 {
251     unsigned Changes = 0;
252     unsigned I;
253
254     /* Walk over the entries */
255     I = 0;
256     while (I < CS_GetEntryCount (S)) {
257
258         const char* Arg;
259
260         /* Get next entry and it's input register values */
261         CodeEntry* E = CS_GetEntry (S, I);
262         const RegContents* In = &E->RI->In;
263
264         /* Assume we have no replacement */
265         CodeEntry* X = 0;
266
267         /* Check the instruction */
268         switch (E->OPC) {
269
270             case OP65_DEA:
271                 if (RegValIsKnown (In->RegA)) {
272                     Arg = MakeHexArg ((In->RegA - 1) & 0xFF);
273                     X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
274                 }
275                 break;
276
277             case OP65_DEX:
278                 if (RegValIsKnown (In->RegX)) {
279                     Arg = MakeHexArg ((In->RegX - 1) & 0xFF);
280                     X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
281                 }
282                 break;
283
284             case OP65_DEY:
285                 if (RegValIsKnown (In->RegY)) {
286                     Arg = MakeHexArg ((In->RegY - 1) & 0xFF);
287                     X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
288                 }
289                 break;
290
291             case OP65_INA:
292                 if (RegValIsKnown (In->RegA)) {
293                     Arg = MakeHexArg ((In->RegA + 1) & 0xFF);
294                     X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
295                 }
296                 break;
297
298             case OP65_INX:
299                 if (RegValIsKnown (In->RegX)) {
300                     Arg = MakeHexArg ((In->RegX + 1) & 0xFF);
301                     X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
302                 }
303                 break;
304
305             case OP65_INY:
306                 if (RegValIsKnown (In->RegY)) {
307                     Arg = MakeHexArg ((In->RegY + 1) & 0xFF);
308                     X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
309                 }
310                 break;
311
312             case OP65_LDA:
313                 if (E->AM == AM65_ZP) {
314                     switch (GetKnownReg (E->Use & REG_ZP, In)) {
315                         case REG_TMP1:
316                             Arg = MakeHexArg (In->Tmp1);
317                             X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
318                             break;
319
320                         case REG_PTR1_LO:
321                             Arg = MakeHexArg (In->Ptr1Lo);
322                             X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
323                             break;
324
325                         case REG_PTR1_HI:
326                             Arg = MakeHexArg (In->Ptr1Hi);
327                             X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
328                             break;
329
330                         case REG_SREG_LO:
331                             Arg = MakeHexArg (In->SRegLo);
332                             X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
333                             break;
334
335                         case REG_SREG_HI:
336                             Arg = MakeHexArg (In->SRegHi);
337                             X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
338                             break;
339                     }
340                 }
341                 break;
342
343             case OP65_LDX:
344                 if (E->AM == AM65_ZP) {
345                     switch (GetKnownReg (E->Use & REG_ZP, In)) {
346                         case REG_TMP1:
347                             Arg = MakeHexArg (In->Tmp1);
348                             X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
349                             break;
350
351                         case REG_PTR1_LO:
352                             Arg = MakeHexArg (In->Ptr1Lo);
353                             X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
354                             break;
355
356                         case REG_PTR1_HI:
357                             Arg = MakeHexArg (In->Ptr1Hi);
358                             X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
359                             break;
360
361                         case REG_SREG_LO:
362                             Arg = MakeHexArg (In->SRegLo);
363                             X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
364                             break;
365
366                         case REG_SREG_HI:
367                             Arg = MakeHexArg (In->SRegHi);
368                             X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
369                             break;
370                     }
371                 }
372                 break;
373
374             case OP65_LDY:
375                 if (E->AM == AM65_ZP) {
376                     switch (GetKnownReg (E->Use, In)) {
377                         case REG_TMP1:
378                             Arg = MakeHexArg (In->Tmp1);
379                             X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
380                             break;
381
382                         case REG_PTR1_LO:
383                             Arg = MakeHexArg (In->Ptr1Lo);
384                             X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
385                             break;
386
387                         case REG_PTR1_HI:
388                             Arg = MakeHexArg (In->Ptr1Hi);
389                             X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
390                             break;
391
392                         case REG_SREG_LO:
393                             Arg = MakeHexArg (In->SRegLo);
394                             X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
395                             break;
396
397                         case REG_SREG_HI:
398                             Arg = MakeHexArg (In->SRegHi);
399                             X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
400                             break;
401                     }
402                 }
403                 break;
404
405             case OP65_TAX:
406                 if (E->RI->In.RegA >= 0) {
407                     Arg = MakeHexArg (In->RegA);
408                     X = NewCodeEntry (OP65_LDX, AM65_IMM, Arg, 0, E->LI);
409                 }
410                 break;
411
412             case OP65_TAY:
413                 if (E->RI->In.RegA >= 0) {
414                     Arg = MakeHexArg (In->RegA);
415                     X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, E->LI);
416                 }
417                 break;
418
419             case OP65_TXA:
420                 if (E->RI->In.RegX >= 0) {
421                     Arg = MakeHexArg (In->RegX);
422                     X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
423                 }
424                 break;
425
426             case OP65_TYA:
427                 if (E->RI->In.RegY >= 0) {
428                     Arg = MakeHexArg (In->RegY);
429                     X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
430                 }
431                 break;
432
433             default:
434                 /* Avoid gcc warnings */
435                 break;
436
437         }
438
439         /* Insert the replacement if we have one */
440         if (X) {
441             CS_InsertEntry (S, X, I+1);
442             CS_DelEntry (S, I);
443             ++Changes;
444         }
445
446         /* Next entry */
447         ++I;
448
449     }
450
451     /* Return the number of changes made */
452     return Changes;
453 }
454
455
456
457 /*****************************************************************************/
458 /*                        Optimize stack pointer ops                         */
459 /*****************************************************************************/
460
461
462
463 static unsigned IsDecSP (const CodeEntry* E)
464 /* Check if this is an insn that decrements the stack pointer. If so, return
465  * the decrement. If not, return zero.
466  * The function expects E to be a subroutine call.
467  */
468 {
469     if (strncmp (E->Arg, "decsp", 5) == 0) {
470         if (E->Arg[5] >= '1' && E->Arg[5] <= '8') {
471             return (E->Arg[5] - '0');
472         }
473     } else if (strcmp (E->Arg, "subysp") == 0 && RegValIsKnown (E->RI->In.RegY)) {
474         return E->RI->In.RegY;
475     }
476
477     /* If we come here, it's not a decsp op */
478     return 0;
479 }
480
481
482
483 static unsigned OptStackPtrOps (CodeSeg* S)
484 /* Merge adjacent calls to decsp into one. NOTE: This function won't merge all
485  * known cases!
486  */
487 {
488     unsigned Changes = 0;
489     unsigned I;
490
491     /* Walk over the entries */
492     I = 0;
493     while (I < CS_GetEntryCount (S)) {
494
495         unsigned Dec1;
496         unsigned Dec2;
497         const CodeEntry* N;
498
499         /* Get the next entry */
500         const CodeEntry* E = CS_GetEntry (S, I);
501
502         /* Check for decspn or subysp */
503         if (E->OPC == OP65_JSR                          &&
504             (Dec1 = IsDecSP (E)) > 0                    &&
505             (N = CS_GetNextEntry (S, I)) != 0           &&
506             (Dec2 = IsDecSP (N)) > 0                    &&
507             (Dec1 += Dec2) <= 255                       &&
508             !CE_HasLabel (N)) {
509
510             CodeEntry* X;
511             char Buf[20];
512
513             /* We can combine the two */
514             if (Dec1 <= 8) {
515                 /* Insert a call to decsp */
516                 xsprintf (Buf, sizeof (Buf), "decsp%u", Dec1);
517                 X = NewCodeEntry (OP65_JSR, AM65_ABS, Buf, 0, N->LI);
518                 CS_InsertEntry (S, X, I+2);
519             } else {
520                 /* Insert a call to subysp */
521                 const char* Arg = MakeHexArg (Dec1);
522                 X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, N->LI);
523                 CS_InsertEntry (S, X, I+2);
524                 X = NewCodeEntry (OP65_JSR, AM65_ABS, "subysp", 0, N->LI);
525                 CS_InsertEntry (S, X, I+3);
526             }
527
528             /* Delete the old code */
529             CS_DelEntries (S, I, 2);
530
531             /* Regenerate register info */
532             CS_GenRegInfo (S);
533
534             /* Remember we had changes */
535             ++Changes;
536
537         } else {
538
539             /* Next entry */
540             ++I;
541         }
542
543     }
544
545     /* Return the number of changes made */
546     return Changes;
547 }
548
549
550
551 /*****************************************************************************/
552 /*                              struct OptFunc                               */
553 /*****************************************************************************/
554
555
556
557 typedef struct OptFunc OptFunc;
558 struct OptFunc {
559     unsigned       (*Func) (CodeSeg*);  /* Optimizer function */
560     const char*    Name;                /* Name of the function/group */
561     unsigned       CodeSizeFactor;      /* Code size factor for this opt func */
562     unsigned long  TotalRuns;           /* Total number of runs */
563     unsigned long  LastRuns;            /* Last number of runs */
564     unsigned long  TotalChanges;        /* Total number of changes */
565     unsigned long  LastChanges;         /* Last number of changes */
566     char           Disabled;            /* True if function disabled */
567 };
568
569
570
571 /*****************************************************************************/
572 /*                                   Code                                    */
573 /*****************************************************************************/
574
575
576
577 /* A list of all the function descriptions */
578 static OptFunc DOpt65C02BitOps  = { Opt65C02BitOps,  "Opt65C02BitOps",   66, 0, 0, 0, 0, 0 };
579 static OptFunc DOpt65C02Ind     = { Opt65C02Ind,     "Opt65C02Ind",     100, 0, 0, 0, 0, 0 };
580 static OptFunc DOpt65C02Stores  = { Opt65C02Stores,  "Opt65C02Stores",  100, 0, 0, 0, 0, 0 };
581 static OptFunc DOptAdd1         = { OptAdd1,         "OptAdd1",         125, 0, 0, 0, 0, 0 };
582 static OptFunc DOptAdd2         = { OptAdd2,         "OptAdd2",         200, 0, 0, 0, 0, 0 };
583 static OptFunc DOptAdd3         = { OptAdd3,         "OptAdd3",          65, 0, 0, 0, 0, 0 };
584 static OptFunc DOptAdd4         = { OptAdd4,         "OptAdd4",          90, 0, 0, 0, 0, 0 };
585 static OptFunc DOptAdd5         = { OptAdd5,         "OptAdd5",         100, 0, 0, 0, 0, 0 };
586 static OptFunc DOptAdd6         = { OptAdd6,         "OptAdd6",          40, 0, 0, 0, 0, 0 };
587 static OptFunc DOptBNegA1       = { OptBNegA1,       "OptBNegA1",       100, 0, 0, 0, 0, 0 };
588 static OptFunc DOptBNegA2       = { OptBNegA2,       "OptBNegA2",       100, 0, 0, 0, 0, 0 };
589 static OptFunc DOptBNegAX1      = { OptBNegAX1,      "OptBNegAX1",      100, 0, 0, 0, 0, 0 };
590 static OptFunc DOptBNegAX2      = { OptBNegAX2,      "OptBNegAX2",      100, 0, 0, 0, 0, 0 };
591 static OptFunc DOptBNegAX3      = { OptBNegAX3,      "OptBNegAX3",      100, 0, 0, 0, 0, 0 };
592 static OptFunc DOptBNegAX4      = { OptBNegAX4,      "OptBNegAX4",      100, 0, 0, 0, 0, 0 };
593 static OptFunc DOptBoolTrans    = { OptBoolTrans,    "OptBoolTrans",    100, 0, 0, 0, 0, 0 };
594 static OptFunc DOptBranchDist   = { OptBranchDist,   "OptBranchDist",     0, 0, 0, 0, 0, 0 };
595 static OptFunc DOptCmp1         = { OptCmp1,         "OptCmp1",          42, 0, 0, 0, 0, 0 };
596 static OptFunc DOptCmp2         = { OptCmp2,         "OptCmp2",          85, 0, 0, 0, 0, 0 };
597 static OptFunc DOptCmp3         = { OptCmp3,         "OptCmp3",          75, 0, 0, 0, 0, 0 };
598 static OptFunc DOptCmp4         = { OptCmp4,         "OptCmp4",          75, 0, 0, 0, 0, 0 };
599 static OptFunc DOptCmp5         = { OptCmp5,         "OptCmp5",         100, 0, 0, 0, 0, 0 };
600 static OptFunc DOptCmp6         = { OptCmp6,         "OptCmp6",         100, 0, 0, 0, 0, 0 };
601 static OptFunc DOptCmp7         = { OptCmp7,         "OptCmp7",          85, 0, 0, 0, 0, 0 };
602 static OptFunc DOptCmp8         = { OptCmp8,         "OptCmp8",          50, 0, 0, 0, 0, 0 };
603 static OptFunc DOptCmp9         = { OptCmp9,         "OptCmp9",          85, 0, 0, 0, 0, 0 };
604 static OptFunc DOptCondBranches1= { OptCondBranches1,"OptCondBranches1", 80, 0, 0, 0, 0, 0 };
605 static OptFunc DOptCondBranches2= { OptCondBranches2,"OptCondBranches2",  0, 0, 0, 0, 0, 0 };
606 static OptFunc DOptDeadCode     = { OptDeadCode,     "OptDeadCode",     100, 0, 0, 0, 0, 0 };
607 static OptFunc DOptDeadJumps    = { OptDeadJumps,    "OptDeadJumps",    100, 0, 0, 0, 0, 0 };
608 static OptFunc DOptDecouple     = { OptDecouple,     "OptDecouple",     100, 0, 0, 0, 0, 0 };
609 static OptFunc DOptDupLoads     = { OptDupLoads,     "OptDupLoads",       0, 0, 0, 0, 0, 0 };
610 static OptFunc DOptIndLoads1    = { OptIndLoads1,    "OptIndLoads1",      0, 0, 0, 0, 0, 0 };
611 static OptFunc DOptIndLoads2    = { OptIndLoads2,    "OptIndLoads2",      0, 0, 0, 0, 0, 0 };
612 static OptFunc DOptJumpCascades = { OptJumpCascades, "OptJumpCascades", 100, 0, 0, 0, 0, 0 };
613 static OptFunc DOptJumpTarget1  = { OptJumpTarget1,  "OptJumpTarget1",  100, 0, 0, 0, 0, 0 };
614 static OptFunc DOptJumpTarget2  = { OptJumpTarget2,  "OptJumpTarget2",  100, 0, 0, 0, 0, 0 };
615 static OptFunc DOptJumpTarget3  = { OptJumpTarget3,  "OptJumpTarget3",  100, 0, 0, 0, 0, 0 };
616 static OptFunc DOptLoad1        = { OptLoad1,        "OptLoad1",        100, 0, 0, 0, 0, 0 };
617 static OptFunc DOptLoad2        = { OptLoad2,        "OptLoad2",        200, 0, 0, 0, 0, 0 };
618 static OptFunc DOptNegAX1       = { OptNegAX1,       "OptNegAX1",       165, 0, 0, 0, 0, 0 };
619 static OptFunc DOptNegAX2       = { OptNegAX2,       "OptNegAX2",       200, 0, 0, 0, 0, 0 };
620 static OptFunc DOptRTS          = { OptRTS,          "OptRTS",          100, 0, 0, 0, 0, 0 };
621 static OptFunc DOptRTSJumps1    = { OptRTSJumps1,    "OptRTSJumps1",    100, 0, 0, 0, 0, 0 };
622 static OptFunc DOptRTSJumps2    = { OptRTSJumps2,    "OptRTSJumps2",    100, 0, 0, 0, 0, 0 };
623 static OptFunc DOptPrecalc      = { OptPrecalc,      "OptPrecalc",      100, 0, 0, 0, 0, 0 };
624 static OptFunc DOptPtrLoad1     = { OptPtrLoad1,     "OptPtrLoad1",     100, 0, 0, 0, 0, 0 };
625 static OptFunc DOptPtrLoad2     = { OptPtrLoad2,     "OptPtrLoad2",     100, 0, 0, 0, 0, 0 };
626 static OptFunc DOptPtrLoad3     = { OptPtrLoad3,     "OptPtrLoad3",     100, 0, 0, 0, 0, 0 };
627 static OptFunc DOptPtrLoad4     = { OptPtrLoad4,     "OptPtrLoad4",     100, 0, 0, 0, 0, 0 };
628 static OptFunc DOptPtrLoad5     = { OptPtrLoad5,     "OptPtrLoad5",      50, 0, 0, 0, 0, 0 };
629 static OptFunc DOptPtrLoad6     = { OptPtrLoad6,     "OptPtrLoad6",      60, 0, 0, 0, 0, 0 };
630 static OptFunc DOptPtrLoad7     = { OptPtrLoad7,     "OptPtrLoad7",     140, 0, 0, 0, 0, 0 };
631 static OptFunc DOptPtrLoad11    = { OptPtrLoad11,    "OptPtrLoad11",     92, 0, 0, 0, 0, 0 };
632 static OptFunc DOptPtrLoad12    = { OptPtrLoad12,    "OptPtrLoad12",     50, 0, 0, 0, 0, 0 };
633 static OptFunc DOptPtrLoad13    = { OptPtrLoad13,    "OptPtrLoad13",     65, 0, 0, 0, 0, 0 };
634 static OptFunc DOptPtrLoad14    = { OptPtrLoad14,    "OptPtrLoad14",    108, 0, 0, 0, 0, 0 };
635 static OptFunc DOptPtrLoad15    = { OptPtrLoad15,    "OptPtrLoad15",     86, 0, 0, 0, 0, 0 };
636 static OptFunc DOptPtrLoad16    = { OptPtrLoad16,    "OptPtrLoad16",    100, 0, 0, 0, 0, 0 };
637 static OptFunc DOptPtrLoad17    = { OptPtrLoad17,    "OptPtrLoad17",    190, 0, 0, 0, 0, 0 };
638 static OptFunc DOptPtrStore1    = { OptPtrStore1,    "OptPtrStore1",     65, 0, 0, 0, 0, 0 };
639 static OptFunc DOptPtrStore2    = { OptPtrStore2,    "OptPtrStore2",     65, 0, 0, 0, 0, 0 };
640 static OptFunc DOptPtrStore3    = { OptPtrStore3,    "OptPtrStore3",    100, 0, 0, 0, 0, 0 };
641 static OptFunc DOptPush1        = { OptPush1,        "OptPush1",         65, 0, 0, 0, 0, 0 };
642 static OptFunc DOptPush2        = { OptPush2,        "OptPush2",         50, 0, 0, 0, 0, 0 };
643 static OptFunc DOptPushPop      = { OptPushPop,      "OptPushPop",        0, 0, 0, 0, 0, 0 };
644 static OptFunc DOptShift1       = { OptShift1,       "OptShift1",       100, 0, 0, 0, 0, 0 };
645 static OptFunc DOptShift2       = { OptShift2,       "OptShift2",       100, 0, 0, 0, 0, 0 };
646 static OptFunc DOptShift3       = { OptShift3,       "OptShift3",        17, 0, 0, 0, 0, 0 };
647 static OptFunc DOptShift4       = { OptShift4,       "OptShift4",       100, 0, 0, 0, 0, 0 };
648 static OptFunc DOptShift5       = { OptShift5,       "OptShift5",       110, 0, 0, 0, 0, 0 };
649 static OptFunc DOptShift6       = { OptShift6,       "OptShift6",       200, 0, 0, 0, 0, 0 };
650 static OptFunc DOptSize1        = { OptSize1,        "OptSize1",        100, 0, 0, 0, 0, 0 };
651 static OptFunc DOptSize2        = { OptSize2,        "OptSize2",        100, 0, 0, 0, 0, 0 };
652 static OptFunc DOptStackOps     = { OptStackOps,     "OptStackOps",     100, 0, 0, 0, 0, 0 };
653 static OptFunc DOptStackPtrOps  = { OptStackPtrOps,  "OptStackPtrOps",   50, 0, 0, 0, 0, 0 };
654 static OptFunc DOptStore1       = { OptStore1,       "OptStore1",        70, 0, 0, 0, 0, 0 };
655 static OptFunc DOptStore2       = { OptStore2,       "OptStore2",       115, 0, 0, 0, 0, 0 };
656 static OptFunc DOptStore3       = { OptStore3,       "OptStore3",       120, 0, 0, 0, 0, 0 };
657 static OptFunc DOptStore4       = { OptStore4,       "OptStore4",        50, 0, 0, 0, 0, 0 };
658 static OptFunc DOptStore5       = { OptStore5,       "OptStore5",       100, 0, 0, 0, 0, 0 };
659 static OptFunc DOptStoreLoad    = { OptStoreLoad,    "OptStoreLoad",      0, 0, 0, 0, 0, 0 };
660 static OptFunc DOptSub1         = { OptSub1,         "OptSub1",         100, 0, 0, 0, 0, 0 };
661 static OptFunc DOptSub2         = { OptSub2,         "OptSub2",         100, 0, 0, 0, 0, 0 };
662 static OptFunc DOptSub3         = { OptSub3,         "OptSub3",         100, 0, 0, 0, 0, 0 };
663 static OptFunc DOptTest1        = { OptTest1,        "OptTest1",         65, 0, 0, 0, 0, 0 };
664 static OptFunc DOptTest2        = { OptTest2,        "OptTest2",         50, 0, 0, 0, 0, 0 };
665 static OptFunc DOptTransfers1   = { OptTransfers1,   "OptTransfers1",     0, 0, 0, 0, 0, 0 };
666 static OptFunc DOptTransfers2   = { OptTransfers2,   "OptTransfers2",    60, 0, 0, 0, 0, 0 };
667 static OptFunc DOptTransfers3   = { OptTransfers3,   "OptTransfers3",    65, 0, 0, 0, 0, 0 };
668 static OptFunc DOptTransfers4   = { OptTransfers4,   "OptTransfers4",    65, 0, 0, 0, 0, 0 };
669 static OptFunc DOptUnusedLoads  = { OptUnusedLoads,  "OptUnusedLoads",    0, 0, 0, 0, 0, 0 };
670 static OptFunc DOptUnusedStores = { OptUnusedStores, "OptUnusedStores",   0, 0, 0, 0, 0, 0 };
671
672
673 /* Table containing all the steps in alphabetical order */
674 static OptFunc* OptFuncs[] = {
675     &DOpt65C02BitOps,
676     &DOpt65C02Ind,
677     &DOpt65C02Stores,
678     &DOptAdd1,
679     &DOptAdd2,
680     &DOptAdd3,
681     &DOptAdd4,
682     &DOptAdd5,
683     &DOptAdd6,
684     &DOptBNegA1,
685     &DOptBNegA2,
686     &DOptBNegAX1,
687     &DOptBNegAX2,
688     &DOptBNegAX3,
689     &DOptBNegAX4,
690     &DOptBoolTrans,
691     &DOptBranchDist,
692     &DOptCmp1,
693     &DOptCmp2,
694     &DOptCmp3,
695     &DOptCmp4,
696     &DOptCmp5,
697     &DOptCmp6,
698     &DOptCmp7,
699     &DOptCmp8,
700     &DOptCmp9,
701     &DOptCondBranches1,
702     &DOptCondBranches2,
703     &DOptDeadCode,
704     &DOptDeadJumps,
705     &DOptDecouple,
706     &DOptDupLoads,
707     &DOptIndLoads1,
708     &DOptIndLoads2,
709     &DOptJumpCascades,
710     &DOptJumpTarget1,
711     &DOptJumpTarget2,
712     &DOptJumpTarget3,
713     &DOptLoad1,
714     &DOptLoad2,
715     &DOptNegAX1,
716     &DOptNegAX2,
717     &DOptPrecalc,
718     &DOptPtrLoad1,
719     &DOptPtrLoad11,
720     &DOptPtrLoad12,
721     &DOptPtrLoad13,
722     &DOptPtrLoad14,
723     &DOptPtrLoad15,
724     &DOptPtrLoad16,
725     &DOptPtrLoad17,
726     &DOptPtrLoad2,
727     &DOptPtrLoad3,
728     &DOptPtrLoad4,
729     &DOptPtrLoad5,
730     &DOptPtrLoad6,
731     &DOptPtrLoad7,
732     &DOptPtrStore1,
733     &DOptPtrStore2,
734     &DOptPtrStore3,
735     &DOptPush1,
736     &DOptPush2,
737     &DOptPushPop,
738     &DOptRTS,
739     &DOptRTSJumps1,
740     &DOptRTSJumps2,
741     &DOptShift1,
742     &DOptShift2,
743     &DOptShift3,
744     &DOptShift4,
745     &DOptShift5,
746     &DOptShift6,
747     &DOptSize1,
748     &DOptSize2,
749     &DOptStackOps,
750     &DOptStackPtrOps,
751     &DOptStore1,
752     &DOptStore2,
753     &DOptStore3,
754     &DOptStore4,
755     &DOptStore5,
756     &DOptStoreLoad,
757     &DOptSub1,
758     &DOptSub2,
759     &DOptSub3,
760     &DOptTest1,
761     &DOptTest2,
762     &DOptTransfers1,
763     &DOptTransfers2,
764     &DOptTransfers3,
765     &DOptTransfers4,
766     &DOptUnusedLoads,
767     &DOptUnusedStores,
768 };
769 #define OPTFUNC_COUNT  (sizeof(OptFuncs) / sizeof(OptFuncs[0]))
770
771
772
773 static int CmpOptStep (const void* Key, const void* Func)
774 /* Compare function for bsearch */
775 {
776     return strcmp (Key, (*(const OptFunc**)Func)->Name);
777 }
778
779
780
781 static OptFunc* FindOptFunc (const char* Name)
782 /* Find an optimizer step by name in the table and return a pointer. Return
783  * NULL if no such step is found.
784  */
785 {
786     /* Search for the function in the list */
787     OptFunc** O = bsearch (Name, OptFuncs, OPTFUNC_COUNT, sizeof (OptFuncs[0]), CmpOptStep);
788     return O? *O : 0;
789 }
790
791
792
793 static OptFunc* GetOptFunc (const char* Name)
794 /* Find an optimizer step by name in the table and return a pointer. Print an
795  * error and call AbEnd if not found.
796  */
797 {
798     /* Search for the function in the list */
799     OptFunc* F = FindOptFunc (Name);
800     if (F == 0) {
801         /* Not found */
802         AbEnd ("Optimization step `%s' not found", Name);
803     }
804     return F;
805 }
806
807
808
809 void DisableOpt (const char* Name)
810 /* Disable the optimization with the given name */
811 {
812     if (strcmp (Name, "any") == 0) {
813         unsigned I;
814         for (I = 0; I < OPTFUNC_COUNT; ++I) {
815             OptFuncs[I]->Disabled = 1;
816         }
817     } else {
818         GetOptFunc(Name)->Disabled = 1;
819     }
820 }
821
822
823
824 void EnableOpt (const char* Name)
825 /* Enable the optimization with the given name */
826 {
827     if (strcmp (Name, "any") == 0) {
828         unsigned I;
829         for (I = 0; I < OPTFUNC_COUNT; ++I) {
830             OptFuncs[I]->Disabled = 0;
831         }
832     } else {
833         GetOptFunc(Name)->Disabled = 0;
834     }
835 }
836
837
838
839 void ListOptSteps (FILE* F)
840 /* List all optimization steps */
841 {
842     unsigned I;
843     for (I = 0; I < OPTFUNC_COUNT; ++I) {
844         fprintf (F, "%s\n", OptFuncs[I]->Name);
845     }
846 }
847
848
849
850 static void ReadOptStats (const char* Name)
851 /* Read the optimizer statistics file */
852 {
853     char Buf [256];
854     unsigned Lines;
855
856     /* Try to open the file */
857     FILE* F = fopen (Name, "r");
858     if (F == 0) {
859         /* Ignore the error */
860         return;
861     }
862
863     /* Read and parse the lines */
864     Lines = 0;
865     while (fgets (Buf, sizeof (Buf), F) != 0) {
866
867         char* B;
868         unsigned Len;
869         OptFunc* Func;
870
871         /* Fields */
872         char Name[32];
873         unsigned long  TotalRuns;
874         unsigned long  TotalChanges;
875
876         /* Count lines */
877         ++Lines;
878
879         /* Remove trailing white space including the line terminator */
880         B = Buf;
881         Len = strlen (B);
882         while (Len > 0 && IsSpace (B[Len-1])) {
883             --Len;
884         }
885         B[Len] = '\0';
886
887         /* Remove leading whitespace */
888         while (IsSpace (*B)) {
889             ++B;
890         }
891
892         /* Check for empty and comment lines */
893         if (*B == '\0' || *B == ';' || *B == '#') {
894             continue;
895         }
896
897         /* Parse the line */
898         if (sscanf (B, "%31s %lu %*u %lu %*u", Name, &TotalRuns, &TotalChanges) != 3) {
899             /* Syntax error */
900             continue;
901         }
902
903         /* Search for the optimizer step. */
904         Func = FindOptFunc (Name);
905         if (Func == 0) {
906             /* Not found */
907             continue;
908         }
909
910         /* Found the step, set the fields */
911         Func->TotalRuns    = TotalRuns;
912         Func->TotalChanges = TotalChanges;
913
914     }
915
916     /* Close the file, ignore errors here. */
917     fclose (F);
918 }
919
920
921
922 static void WriteOptStats (const char* Name)
923 /* Write the optimizer statistics file */
924 {
925     unsigned I;
926
927     /* Try to open the file */
928     FILE* F = fopen (Name, "w");
929     if (F == 0) {
930         /* Ignore the error */
931         return;
932     }
933
934     /* Write a header */
935     fprintf (F,
936              "; Optimizer               Total      Last       Total      Last\n"
937              ";   Step                  Runs       Runs        Chg       Chg\n");
938
939
940     /* Write the data */
941     for (I = 0; I < OPTFUNC_COUNT; ++I) {
942         const OptFunc* O = OptFuncs[I];
943         fprintf (F,
944                  "%-20s %10lu %10lu %10lu %10lu\n",
945                  O->Name,
946                  O->TotalRuns,
947                  O->LastRuns,
948                  O->TotalChanges,
949                  O->LastChanges);
950     }
951
952     /* Close the file, ignore errors here. */
953     fclose (F);
954 }
955
956
957
958 static unsigned RunOptFunc (CodeSeg* S, OptFunc* F, unsigned Max)
959 /* Run one optimizer function Max times or until there are no more changes */
960 {
961     unsigned Changes, C;
962
963     /* Don't run the function if it is disabled or if it is prohibited by the
964      * code size factor
965      */
966     if (F->Disabled || F->CodeSizeFactor > S->CodeSizeFactor) {
967         return 0;
968     }
969
970     /* Run this until there are no more changes */
971     Changes = 0;
972     do {
973
974         /* Run the function */
975         C = F->Func (S);
976         if (Debug && C > 0) {
977             printf ("Applied %s: %u changes\n", F->Name, C);
978         }
979         Changes += C;
980
981         /* Do statistics */
982         ++F->TotalRuns;
983         ++F->LastRuns;
984         F->TotalChanges += C;
985         F->LastChanges  += C;
986
987         /* If we had changes, regenerate register info */
988         if (C) {
989             CS_GenRegInfo (S);
990         }
991
992     } while (--Max && C > 0);
993
994     /* Return the number of changes */
995     return Changes;
996 }
997
998
999
1000 static unsigned RunOptGroup1 (CodeSeg* S)
1001 /* Run the first group of optimization steps. These steps translate known
1002  * patterns emitted by the code generator into more optimal patterns. Order
1003  * of the steps is important, because some of the steps done earlier cover
1004  * the same patterns as later steps as subpatterns.
1005  */
1006 {
1007     unsigned Changes = 0;
1008
1009     Changes += RunOptFunc (S, &DOptStackPtrOps, 5);
1010     Changes += RunOptFunc (S, &DOptPtrStore1, 1);
1011     Changes += RunOptFunc (S, &DOptPtrStore2, 1);
1012     Changes += RunOptFunc (S, &DOptPtrStore3, 1);
1013     Changes += RunOptFunc (S, &DOptAdd3, 1);    /* Before OptPtrLoad5! */
1014     Changes += RunOptFunc (S, &DOptPtrLoad1, 1);
1015     Changes += RunOptFunc (S, &DOptPtrLoad2, 1);
1016     Changes += RunOptFunc (S, &DOptPtrLoad3, 1);
1017     Changes += RunOptFunc (S, &DOptPtrLoad4, 1);
1018     Changes += RunOptFunc (S, &DOptPtrLoad5, 1);
1019     Changes += RunOptFunc (S, &DOptPtrLoad6, 1);
1020     Changes += RunOptFunc (S, &DOptPtrLoad7, 1);
1021     Changes += RunOptFunc (S, &DOptPtrLoad11, 1);
1022     Changes += RunOptFunc (S, &DOptPtrLoad12, 1);
1023     Changes += RunOptFunc (S, &DOptPtrLoad13, 1);
1024     Changes += RunOptFunc (S, &DOptPtrLoad14, 1);
1025     Changes += RunOptFunc (S, &DOptPtrLoad15, 1);
1026     Changes += RunOptFunc (S, &DOptPtrLoad16, 1);
1027     Changes += RunOptFunc (S, &DOptPtrLoad17, 1);
1028     Changes += RunOptFunc (S, &DOptBNegAX1, 1);
1029     Changes += RunOptFunc (S, &DOptBNegAX2, 1);
1030     Changes += RunOptFunc (S, &DOptBNegAX3, 1);
1031     Changes += RunOptFunc (S, &DOptBNegAX4, 1);
1032     Changes += RunOptFunc (S, &DOptAdd1, 1);
1033     Changes += RunOptFunc (S, &DOptAdd2, 1);
1034     Changes += RunOptFunc (S, &DOptAdd4, 1);
1035     Changes += RunOptFunc (S, &DOptAdd5, 1);
1036     Changes += RunOptFunc (S, &DOptAdd6, 1);
1037     Changes += RunOptFunc (S, &DOptSub1, 1);
1038     Changes += RunOptFunc (S, &DOptSub3, 1);
1039     Changes += RunOptFunc (S, &DOptStore4, 1);
1040     Changes += RunOptFunc (S, &DOptStore5, 1);
1041     Changes += RunOptFunc (S, &DOptShift1, 1);
1042     Changes += RunOptFunc (S, &DOptShift2, 1);
1043     Changes += RunOptFunc (S, &DOptShift5, 1);
1044     Changes += RunOptFunc (S, &DOptShift6, 1);
1045     Changes += RunOptFunc (S, &DOptStore1, 1);
1046     Changes += RunOptFunc (S, &DOptStore2, 5);
1047     Changes += RunOptFunc (S, &DOptStore3, 5);
1048
1049     /* Return the number of changes */
1050     return Changes;
1051 }
1052
1053
1054
1055 static unsigned RunOptGroup2 (CodeSeg* S)
1056 /* Run one group of optimization steps. This step involves just decoupling
1057  * instructions by replacing them by instructions that do not depend on
1058  * previous instructions. This makes it easier to find instructions that
1059  * aren't used.
1060  */
1061 {
1062     unsigned Changes = 0;
1063
1064     Changes += RunOptFunc (S, &DOptDecouple, 1);
1065
1066     /* Return the number of changes */
1067     return Changes;
1068 }
1069
1070
1071
1072 static unsigned RunOptGroup3 (CodeSeg* S)
1073 /* Run one group of optimization steps. These steps depend on each other,
1074  * that means that one step may allow another step to do additional work,
1075  * so we will repeat the steps as long as we see any changes.
1076  */
1077 {
1078     unsigned Changes, C;
1079
1080     Changes = 0;
1081     do {
1082         C = 0;
1083
1084         C += RunOptFunc (S, &DOptBNegA1, 1);
1085         C += RunOptFunc (S, &DOptBNegA2, 1);
1086         C += RunOptFunc (S, &DOptNegAX1, 1);
1087         C += RunOptFunc (S, &DOptNegAX2, 1);
1088         C += RunOptFunc (S, &DOptStackOps, 3);
1089         C += RunOptFunc (S, &DOptShift1, 1);
1090         C += RunOptFunc (S, &DOptShift4, 1);
1091         C += RunOptFunc (S, &DOptSub1, 1);
1092         C += RunOptFunc (S, &DOptSub2, 1);
1093         C += RunOptFunc (S, &DOptSub3, 1);
1094         C += RunOptFunc (S, &DOptAdd5, 1);
1095         C += RunOptFunc (S, &DOptAdd6, 1);
1096         C += RunOptFunc (S, &DOptJumpCascades, 1);
1097         C += RunOptFunc (S, &DOptDeadJumps, 1);
1098         C += RunOptFunc (S, &DOptRTS, 1);
1099         C += RunOptFunc (S, &DOptDeadCode, 1);
1100         C += RunOptFunc (S, &DOptBoolTrans, 1);
1101         C += RunOptFunc (S, &DOptJumpTarget1, 1);
1102         C += RunOptFunc (S, &DOptJumpTarget2, 1);
1103         C += RunOptFunc (S, &DOptCondBranches1, 1);
1104         C += RunOptFunc (S, &DOptCondBranches2, 1);
1105         C += RunOptFunc (S, &DOptRTSJumps1, 1);
1106         C += RunOptFunc (S, &DOptCmp1, 1);
1107         C += RunOptFunc (S, &DOptCmp2, 1);
1108         C += RunOptFunc (S, &DOptCmp3, 1);
1109         C += RunOptFunc (S, &DOptCmp4, 1);
1110         C += RunOptFunc (S, &DOptCmp5, 1);
1111         C += RunOptFunc (S, &DOptCmp6, 1);
1112         C += RunOptFunc (S, &DOptCmp7, 1);
1113         C += RunOptFunc (S, &DOptCmp8, 1);
1114         C += RunOptFunc (S, &DOptCmp9, 1);
1115         C += RunOptFunc (S, &DOptTest1, 1);
1116         C += RunOptFunc (S, &DOptLoad1, 1);
1117         C += RunOptFunc (S, &DOptJumpTarget3, 1);       /* After OptCondBranches2 */
1118         C += RunOptFunc (S, &DOptUnusedLoads, 1);
1119         C += RunOptFunc (S, &DOptUnusedStores, 1);
1120         C += RunOptFunc (S, &DOptDupLoads, 1);
1121         C += RunOptFunc (S, &DOptStoreLoad, 1);
1122         C += RunOptFunc (S, &DOptTransfers1, 1);
1123         C += RunOptFunc (S, &DOptTransfers3, 1);
1124         C += RunOptFunc (S, &DOptTransfers4, 1);
1125         C += RunOptFunc (S, &DOptStore1, 1);
1126         C += RunOptFunc (S, &DOptStore5, 1);
1127         C += RunOptFunc (S, &DOptPushPop, 1);
1128         C += RunOptFunc (S, &DOptPrecalc, 1);
1129
1130         Changes += C;
1131
1132     } while (C);
1133
1134     /* Return the number of changes */
1135     return Changes;
1136 }
1137
1138
1139
1140 static unsigned RunOptGroup4 (CodeSeg* S)
1141 /* Run another round of pattern replacements. These are done late, since there
1142  * may be better replacements before.
1143  */
1144 {
1145     unsigned Changes = 0;
1146
1147     /* Repeat some of the steps here */
1148     Changes += RunOptFunc (S, &DOptShift3, 1);
1149     Changes += RunOptFunc (S, &DOptPush1, 1);
1150     Changes += RunOptFunc (S, &DOptPush2, 1);
1151     Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
1152     Changes += RunOptFunc (S, &DOptTest2, 1);
1153     Changes += RunOptFunc (S, &DOptTransfers2, 1);
1154     Changes += RunOptFunc (S, &DOptLoad2, 1);
1155
1156     /* Return the number of changes */
1157     return Changes;
1158 }
1159
1160
1161
1162 static unsigned RunOptGroup5 (CodeSeg* S)
1163 /* 65C02 specific optimizations. */
1164 {
1165     unsigned Changes = 0;
1166
1167     if (CPUIsets[CPU] & CPU_ISET_65SC02) {
1168         Changes += RunOptFunc (S, &DOpt65C02BitOps, 1);
1169         Changes += RunOptFunc (S, &DOpt65C02Ind, 1);
1170         Changes += RunOptFunc (S, &DOpt65C02Stores, 1);
1171         if (Changes) {
1172             /* The 65C02 replacement codes do often make the use of a register
1173              * value unnecessary, so if we have changes, run another load
1174              * removal pass.
1175              */
1176             Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
1177         }
1178     }
1179
1180     /* Return the number of changes */
1181     return Changes;
1182 }
1183
1184
1185
1186 static unsigned RunOptGroup6 (CodeSeg* S)
1187 /* This one is quite special. It tries to replace "lda (sp),y" by "lda (sp,x)".
1188  * The latter is ony cycle slower, but if we're able to remove the necessary
1189  * load of the Y register, because X is zero anyway, we gain 1 cycle and
1190  * shorten the code by one (transfer) or two bytes (load). So what we do is
1191  * to replace the insns, remove unused loads, and then change back all insns
1192  * where Y is still zero (meaning that the load has not been removed).
1193  */
1194 {
1195     unsigned Changes = 0;
1196
1197     /* This group will only run for a standard 6502, because the 65C02 has a
1198      * better addressing mode that covers this case.
1199      */
1200     if ((CPUIsets[CPU] & CPU_ISET_65SC02) == 0) {
1201         Changes += RunOptFunc (S, &DOptIndLoads1, 1);
1202         Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
1203         Changes += RunOptFunc (S, &DOptIndLoads2, 1);
1204     }
1205
1206     /* Return the number of changes */
1207     return Changes;
1208 }
1209
1210
1211
1212 static unsigned RunOptGroup7 (CodeSeg* S)
1213 /* The last group of optimization steps. Adjust branches, do size optimizations.
1214  */
1215 {
1216     unsigned Changes = 0;
1217     unsigned C;
1218
1219     /* Optimize for size, that is replace operations by shorter ones, even
1220      * if this does hinder further optimizations (no problem since we're
1221      * done soon).
1222      */
1223     C = RunOptFunc (S, &DOptSize1, 1);
1224     if (C) {
1225         Changes += C;
1226         /* Run some optimization passes again, since the size optimizations
1227          * may have opened new oportunities.
1228          */
1229         Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
1230         Changes += RunOptFunc (S, &DOptUnusedStores, 1);
1231         Changes += RunOptFunc (S, &DOptJumpTarget1, 5);
1232         Changes += RunOptFunc (S, &DOptStore5, 1);
1233     }
1234
1235     C = RunOptFunc (S, &DOptSize2, 1);
1236     if (C) {
1237         Changes += C;
1238         /* Run some optimization passes again, since the size optimizations
1239          * may have opened new oportunities.
1240          */
1241         Changes += RunOptFunc (S, &DOptUnusedLoads, 1);
1242         Changes += RunOptFunc (S, &DOptJumpTarget1, 5);
1243         Changes += RunOptFunc (S, &DOptStore5, 1);
1244         Changes += RunOptFunc (S, &DOptTransfers1, 1);
1245         Changes += RunOptFunc (S, &DOptTransfers3, 1);
1246     }
1247
1248     /* Adjust branch distances */
1249     Changes += RunOptFunc (S, &DOptBranchDist, 3);
1250
1251     /* Replace conditional branches to RTS. If we had changes, we must run dead
1252      * code elimination again, since the change may have introduced dead code.
1253      */
1254     C = RunOptFunc (S, &DOptRTSJumps2, 1);
1255     Changes += C;
1256     if (C) {
1257         Changes += RunOptFunc (S, &DOptDeadCode, 1);
1258     }
1259
1260     /* Return the number of changes */
1261     return Changes;
1262 }
1263
1264
1265
1266 void RunOpt (CodeSeg* S)
1267 /* Run the optimizer */
1268 {
1269     const char* StatFileName;
1270
1271     /* If we shouldn't run the optimizer, bail out */
1272     if (!S->Optimize) {
1273         return;
1274     }
1275
1276     /* Check if we are requested to write optimizer statistics */
1277     StatFileName = getenv ("CC65_OPTSTATS");
1278     if (StatFileName) {
1279         ReadOptStats (StatFileName);
1280     }
1281
1282     /* Print the name of the function we are working on */
1283     if (S->Func) {
1284         Print (stdout, 1, "Running optimizer for function `%s'\n", S->Func->Name);
1285     } else {
1286         Print (stdout, 1, "Running optimizer for global code segment\n");
1287     }
1288
1289     /* Generate register info for all instructions */
1290     CS_GenRegInfo (S);
1291
1292     /* Run groups of optimizations */
1293     RunOptGroup1 (S);
1294     RunOptGroup2 (S);
1295     RunOptGroup3 (S);
1296     RunOptGroup4 (S);
1297     RunOptGroup5 (S);
1298     RunOptGroup6 (S);
1299     RunOptGroup7 (S);
1300
1301     /* Free register info */
1302     CS_FreeRegInfo (S);
1303
1304     /* Write statistics */
1305     if (StatFileName) {
1306         WriteOptStats (StatFileName);
1307     }
1308 }
1309
1310
1311