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