]> git.sur5r.net Git - cc65/blob - src/cc65/coptind.c
Fixed wrong code generation for
[cc65] / src / cc65 / coptind.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 coptind.c                                 */
4 /*                                                                           */
5 /*              Environment independent low level optimizations              */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2001-2005, Ullrich von Bassewitz                                      */
10 /*                Römerstraße 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 /* common */
37 #include "cpu.h"
38
39 /* cc65 */
40 #include "codeent.h"
41 #include "codeinfo.h"
42 #include "codeopt.h"
43 #include "error.h"
44 #include "coptind.h"
45
46
47
48 /*****************************************************************************/
49 /*                             Helper functions                              */
50 /*****************************************************************************/
51
52
53
54 static int GetBranchDist (CodeSeg* S, unsigned From, CodeEntry* To)
55 /* Get the branch distance between the two entries and return it. The distance
56  * will be negative for backward jumps and positive for forward jumps.
57  */
58 {
59     /* Get the index of the branch target */
60     unsigned TI = CS_GetEntryIndex (S, To);
61
62     /* Determine the branch distance */
63     int Distance = 0;
64     if (TI >= From) {
65         /* Forward branch, do not count the current insn */
66         unsigned J = From+1;
67         while (J < TI) {
68             CodeEntry* N = CS_GetEntry (S, J++);
69             Distance += N->Size;
70         }
71     } else {
72         /* Backward branch */
73         unsigned J = TI;
74         while (J < From) {
75             CodeEntry* N = CS_GetEntry (S, J++);
76             Distance -= N->Size;
77         }
78     }
79
80     /* Return the calculated distance */
81     return Distance;
82 }
83
84
85
86 static int IsShortDist (int Distance)
87 /* Return true if the given distance is a short branch distance */
88 {
89     return (Distance >= -125 && Distance <= 125);
90 }
91
92
93
94 static short ZPRegVal (unsigned short Use, const RegContents* RC)
95 /* Return the contents of the given zeropage register */
96 {
97     if ((Use & REG_TMP1) != 0) {
98         return RC->Tmp1;
99     } else if ((Use & REG_PTR1_LO) != 0) {
100         return RC->Ptr1Lo;
101     } else if ((Use & REG_PTR1_HI) != 0) {
102         return RC->Ptr1Hi;
103     } else if ((Use & REG_SREG_LO) != 0) {
104         return RC->SRegLo;
105     } else if ((Use & REG_SREG_HI) != 0) {
106         return RC->SRegHi;
107     } else {
108         return UNKNOWN_REGVAL;
109     }
110 }
111
112
113
114 static short RegVal (unsigned short Use, const RegContents* RC)
115 /* Return the contents of the given register */
116 {
117     if ((Use & REG_A) != 0) {
118         return RC->RegA;
119     } else if ((Use & REG_X) != 0) {
120         return RC->RegX;
121     } else if ((Use & REG_Y) != 0) {
122         return RC->RegY;
123     } else {
124         return ZPRegVal (Use, RC);
125     }
126 }
127
128
129
130 /*****************************************************************************/
131 /*                        Replace jumps to RTS by RTS                        */
132 /*****************************************************************************/
133
134
135
136 unsigned OptRTSJumps1 (CodeSeg* S)
137 /* Replace jumps to RTS by RTS */
138 {
139     unsigned Changes = 0;
140
141     /* Walk over all entries minus the last one */
142     unsigned I = 0;
143     while (I < CS_GetEntryCount (S)) {
144
145         /* Get the next entry */
146         CodeEntry* E = CS_GetEntry (S, I);
147
148         /* Check if it's an unconditional branch to a local target */
149         if ((E->Info & OF_UBRA) != 0            &&
150             E->JumpTo != 0                      &&
151             E->JumpTo->Owner->OPC == OP65_RTS) {
152
153             /* Insert an RTS instruction */
154             CodeEntry* X = NewCodeEntry (OP65_RTS, AM65_IMP, 0, 0, E->LI);
155             CS_InsertEntry (S, X, I+1);
156
157             /* Delete the jump */
158             CS_DelEntry (S, I);
159
160             /* Remember, we had changes */
161             ++Changes;
162
163         }
164
165         /* Next entry */
166         ++I;
167
168     }
169
170     /* Return the number of changes made */
171     return Changes;
172 }
173
174
175
176 unsigned OptRTSJumps2 (CodeSeg* S)
177 /* Replace long conditional jumps to RTS */
178 {
179     unsigned Changes = 0;
180
181     /* Walk over all entries minus the last one */
182     unsigned I = 0;
183     while (I < CS_GetEntryCount (S)) {
184
185         CodeEntry* N;
186
187         /* Get the next entry */
188         CodeEntry* E = CS_GetEntry (S, I);
189
190         /* Check if it's an unconditional branch to a local target */
191         if ((E->Info & OF_CBRA) != 0            &&   /* Conditional branch */
192             (E->Info & OF_LBRA) != 0            &&   /* Long branch */
193             E->JumpTo != 0                      &&   /* Local label */
194             E->JumpTo->Owner->OPC == OP65_RTS   &&   /* Target is an RTS */
195             (N = CS_GetNextEntry (S, I)) != 0) {     /* There is a next entry */
196
197             CodeEntry* X;
198             CodeLabel* LN;
199             opc_t      NewBranch;
200
201             /* We will create a jump around an RTS instead of the long branch */
202             X = NewCodeEntry (OP65_RTS, AM65_IMP, 0, 0, E->JumpTo->Owner->LI);
203             CS_InsertEntry (S, X, I+1);
204
205             /* Get the new branch opcode */
206             NewBranch = MakeShortBranch (GetInverseBranch (E->OPC));
207
208             /* Get the label attached to N, create a new one if needed */
209             LN = CS_GenLabel (S, N);
210
211             /* Generate the branch */
212             X = NewCodeEntry (NewBranch, AM65_BRA, LN->Name, LN, E->LI);
213             CS_InsertEntry (S, X, I+1);
214
215             /* Delete the long branch */
216             CS_DelEntry (S, I);
217
218             /* Remember, we had changes */
219             ++Changes;
220
221         }
222
223         /* Next entry */
224         ++I;
225
226     }
227
228     /* Return the number of changes made */
229     return Changes;
230 }
231
232
233
234 /*****************************************************************************/
235 /*                             Remove dead jumps                             */
236 /*****************************************************************************/
237
238
239
240 unsigned OptDeadJumps (CodeSeg* S)
241 /* Remove dead jumps (jumps to the next instruction) */
242 {
243     unsigned Changes = 0;
244
245     /* Walk over all entries minus the last one */
246     unsigned I = 0;
247     while (I < CS_GetEntryCount (S)) {
248
249         /* Get the next entry */
250         CodeEntry* E = CS_GetEntry (S, I);
251
252         /* Check if it's a branch, if it has a local target, and if the target
253          * is the next instruction.
254          */
255         if (E->AM == AM65_BRA                               &&
256             E->JumpTo                                       &&
257             E->JumpTo->Owner == CS_GetNextEntry (S, I)) {
258
259             /* Delete the dead jump */
260             CS_DelEntry (S, I);
261
262             /* Remember, we had changes */
263             ++Changes;
264
265         } else {
266
267             /* Next entry */
268             ++I;
269
270         }
271     }
272
273     /* Return the number of changes made */
274     return Changes;
275 }
276
277
278
279 /*****************************************************************************/
280 /*                             Remove dead code                              */
281 /*****************************************************************************/
282
283
284
285 unsigned OptDeadCode (CodeSeg* S)
286 /* Remove dead code (code that follows an unconditional jump or an rts/rti
287  * and has no label)
288  */
289 {
290     unsigned Changes = 0;
291
292     /* Walk over all entries */
293     unsigned I = 0;
294     while (I < CS_GetEntryCount (S)) {
295
296         CodeEntry* N;
297         CodeLabel* LN;
298
299         /* Get this entry */
300         CodeEntry* E = CS_GetEntry (S, I);
301
302         /* Check if it's an unconditional branch, and if the next entry has
303          * no labels attached, or if the label is just used so that the insn
304          * can jump to itself.
305          */
306         if ((E->Info & OF_DEAD) != 0                     &&     /* Dead code follows */
307             (N = CS_GetNextEntry (S, I)) != 0            &&     /* Has next entry */
308             (!CE_HasLabel (N)                        ||         /* Don't has a label */
309              ((N->Info & OF_UBRA) != 0          &&              /* Uncond branch */
310               (LN = N->JumpTo) != 0             &&              /* Jumps to known label */
311               LN->Owner == N                    &&              /* Attached to insn */
312               CL_GetRefCount (LN) == 1))) {                     /* Only reference */
313
314             /* Delete the next entry */
315             CS_DelEntry (S, I+1);
316
317             /* Remember, we had changes */
318             ++Changes;
319
320         } else {
321
322             /* Next entry */
323             ++I;
324
325         }
326     }
327
328     /* Return the number of changes made */
329     return Changes;
330 }
331
332
333
334 /*****************************************************************************/
335 /*                          Optimize jump cascades                           */
336 /*****************************************************************************/
337
338
339
340 unsigned OptJumpCascades (CodeSeg* S)
341 /* Optimize jump cascades (jumps to jumps). In such a case, the jump is
342  * replaced by a jump to the final location. This will in some cases produce
343  * worse code, because some jump targets are no longer reachable by short
344  * branches, but this is quite rare, so there are more advantages than
345  * disadvantages.
346  */
347 {
348     unsigned Changes = 0;
349
350     /* Walk over all entries */
351     unsigned I = 0;
352     while (I < CS_GetEntryCount (S)) {
353
354         CodeEntry* N;
355         CodeLabel* OldLabel;
356
357         /* Get this entry */
358         CodeEntry* E = CS_GetEntry (S, I);
359
360         /* Check if it's a branch, if it has a jump label, if this jump
361          * label is not attached to the instruction itself, and if the
362          * target instruction is itself a branch.
363          */
364         if ((E->Info & OF_BRA) != 0        &&
365             (OldLabel = E->JumpTo) != 0    &&
366             (N = OldLabel->Owner) != E     &&
367             (N->Info & OF_BRA) != 0) {
368
369             /* Check if we can use the final target label. This is the case,
370              * if the target branch is an absolut branch, or if it is a
371              * conditional branch checking the same condition as the first one.
372              */
373             if ((N->Info & OF_UBRA) != 0 ||
374                 ((E->Info & OF_CBRA) != 0 &&
375                  GetBranchCond (E->OPC)  == GetBranchCond (N->OPC))) {
376
377                 /* This is a jump cascade and we may jump to the final target,
378                  * provided that the other insn does not jump to itself. If
379                  * this is the case, we can also jump to ourselves, otherwise
380                  * insert a jump to the new instruction and remove the old one.
381                  */
382                 CodeEntry* X;
383                 CodeLabel* LN = N->JumpTo;
384
385                 if (LN != 0 && LN->Owner == N) {
386
387                     /* We found a jump to a jump to itself. Replace our jump
388                      * by a jump to itself.
389                      */
390                     CodeLabel* LE = CS_GenLabel (S, E);
391                     X = NewCodeEntry (E->OPC, E->AM, LE->Name, LE, E->LI);
392
393                 } else {
394
395                     /* Jump to the final jump target */
396                     X = NewCodeEntry (E->OPC, E->AM, N->Arg, N->JumpTo, E->LI);
397
398                 }
399
400                 /* Insert it behind E */
401                 CS_InsertEntry (S, X, I+1);
402
403                 /* Remove E */
404                 CS_DelEntry (S, I);
405
406                 /* Remember, we had changes */
407                 ++Changes;
408
409                 /* Done */
410                 continue;
411
412             }
413
414             /* Check if both are conditional branches, and the condition of
415              * the second is the inverse of that of the first. In this case,
416              * the second branch will never be taken, and we may jump directly
417              * to the instruction behind this one.
418              */
419             if ((E->Info & OF_CBRA) != 0 && (N->Info & OF_CBRA) != 0) {
420
421                 CodeEntry* X;   /* Instruction behind N */
422                 CodeLabel* LX;  /* Label attached to X */
423
424                 /* Get the branch conditions of both branches */
425                 bc_t BC1 = GetBranchCond (E->OPC);
426                 bc_t BC2 = GetBranchCond (N->OPC);
427
428                 /* Check the branch conditions */
429                 if (BC1 != GetInverseCond (BC2)) {
430                     /* Condition not met */
431                     goto NextEntry;
432                 }
433
434                 /* We may jump behind this conditional branch. Get the
435                  * pointer to the next instruction
436                  */
437                 if ((X = CS_GetNextEntry (S, CS_GetEntryIndex (S, N))) == 0) {
438                     /* N is the last entry, bail out */
439                     goto NextEntry;
440                 }
441
442                 /* Get the label attached to X, create a new one if needed */
443                 LX = CS_GenLabel (S, X);
444
445                 /* Move the reference from E to the new label */
446                 CS_MoveLabelRef (S, E, LX);
447
448                 /* Remember, we had changes */
449                 ++Changes;
450
451                 /* Done */
452                 continue;
453
454             }
455         }
456
457 NextEntry:
458         /* Next entry */
459         ++I;
460
461     }
462
463     /* Return the number of changes made */
464     return Changes;
465 }
466
467
468
469 /*****************************************************************************/
470 /*                             Optimize jsr/rts                              */
471 /*****************************************************************************/
472
473
474
475 unsigned OptRTS (CodeSeg* S)
476 /* Optimize subroutine calls followed by an RTS. The subroutine call will get
477  * replaced by a jump. Don't bother to delete the RTS if it does not have a
478  * label, the dead code elimination should take care of it.
479  */
480 {
481     unsigned Changes = 0;
482
483     /* Walk over all entries minus the last one */
484     unsigned I = 0;
485     while (I < CS_GetEntryCount (S)) {
486
487         CodeEntry* N;
488
489         /* Get this entry */
490         CodeEntry* E = CS_GetEntry (S, I);
491
492         /* Check if it's a subroutine call and if the following insn is RTS */
493         if (E->OPC == OP65_JSR                    &&
494             (N = CS_GetNextEntry (S, I)) != 0 &&
495             N->OPC == OP65_RTS) {
496
497             /* Change the jsr to a jmp and use the additional info for a jump */
498             E->AM = AM65_BRA;
499             CE_ReplaceOPC (E, OP65_JMP);
500
501             /* Remember, we had changes */
502             ++Changes;
503
504         }
505
506         /* Next entry */
507         ++I;
508
509     }
510
511     /* Return the number of changes made */
512     return Changes;
513 }
514
515
516
517 /*****************************************************************************/
518 /*                           Optimize jump targets                           */
519 /*****************************************************************************/
520
521
522
523 unsigned OptJumpTarget (CodeSeg* S)
524 /* If the instruction preceeding an unconditional branch is the same as the
525  * instruction preceeding the jump target, the jump target may be moved
526  * one entry back. This is a size optimization, since the instruction before
527  * the branch gets removed.
528  */
529 {
530     unsigned Changes = 0;
531     CodeEntry* E1;              /* Entry 1 */
532     CodeEntry* E2;              /* Entry 2 */
533     CodeEntry* T1;              /* Jump target entry 1 */
534     CodeLabel* TL1;             /* Target label 1 */
535
536     /* Walk over the entries */
537     unsigned I = 0;
538     while (I < CS_GetEntryCount (S)) {
539
540         /* Get next entry */
541         E2 = CS_GetNextEntry (S, I);
542
543         /* Check if we have a jump or branch, and a matching label, which
544          * is not attached to the jump itself
545          */
546         if (E2 != 0                     &&
547             (E2->Info & OF_UBRA) != 0   &&
548             E2->JumpTo                  &&
549             E2->JumpTo->Owner != E2) {
550
551             /* Get the entry preceeding the branch target */
552             T1 = CS_GetPrevEntry (S, CS_GetEntryIndex (S, E2->JumpTo->Owner));
553             if (T1 == 0) {
554                 /* There is no such entry */
555                 goto NextEntry;
556             }
557
558             /* Get the entry preceeding the jump */
559             E1 = CS_GetEntry (S, I);
560
561             /* Check if both preceeding instructions are identical */
562             if (!CodeEntriesAreEqual (E1, T1)) {
563                 /* Not equal, try next */
564                 goto NextEntry;
565             }
566
567             /* Get the label for the instruction preceeding the jump target.
568              * This routine will create a new label if the instruction does
569              * not already have one.
570              */
571             TL1 = CS_GenLabel (S, T1);
572
573             /* Change the jump target to point to this new label */
574             CS_MoveLabelRef (S, E2, TL1);
575
576             /* If the instruction preceeding the jump has labels attached,
577              * move references to this label to the new label.
578              */
579             if (CE_HasLabel (E1)) {
580                 CS_MoveLabels (S, E1, T1);
581             }
582
583             /* Remove the entry preceeding the jump */
584             CS_DelEntry (S, I);
585
586             /* Remember, we had changes */
587             ++Changes;
588
589         } else {
590 NextEntry:
591             /* Next entry */
592             ++I;
593         }
594     }
595
596     /* Return the number of changes made */
597     return Changes;
598 }
599
600
601
602 /*****************************************************************************/
603 /*                       Optimize conditional branches                       */
604 /*****************************************************************************/
605
606
607
608 unsigned OptCondBranches (CodeSeg* S)
609 /* Performs several optimization steps:
610  *
611  *  - If an immidiate load of a register is followed by a conditional jump that
612  *    is never taken because the load of the register sets the flags in such a
613  *    manner, remove the conditional branch.
614  *  - If the conditional branch is always taken because of the register load,
615  *    replace it by a jmp.
616  *  - If a conditional branch jumps around an unconditional branch, remove the
617  *    conditional branch and make the jump a conditional branch with the
618  *    inverse condition of the first one.
619  */
620 {
621     unsigned Changes = 0;
622
623     /* Walk over the entries */
624     unsigned I = 0;
625     while (I < CS_GetEntryCount (S)) {
626
627         CodeEntry* N;
628         CodeLabel* L;
629
630         /* Get next entry */
631         CodeEntry* E = CS_GetEntry (S, I);
632
633         /* Check if it's a register load */
634         if ((E->Info & OF_LOAD) != 0              &&  /* It's a load instruction */
635             E->AM == AM65_IMM                     &&  /* ..with immidiate addressing */
636             (E->Flags & CEF_NUMARG) != 0          &&  /* ..and a numeric argument. */
637             (N = CS_GetNextEntry (S, I)) != 0     &&  /* There is a following entry */
638             (N->Info & OF_CBRA) != 0              &&  /* ..which is a conditional branch */
639             !CE_HasLabel (N)) {               /* ..and does not have a label */
640
641             /* Get the branch condition */
642             bc_t BC = GetBranchCond (N->OPC);
643
644             /* Check the argument against the branch condition */
645             if ((BC == BC_EQ && E->Num != 0)            ||
646                 (BC == BC_NE && E->Num == 0)            ||
647                 (BC == BC_PL && (E->Num & 0x80) != 0)   ||
648                 (BC == BC_MI && (E->Num & 0x80) == 0)) {
649
650                 /* Remove the conditional branch */
651                 CS_DelEntry (S, I+1);
652
653                 /* Remember, we had changes */
654                 ++Changes;
655
656             } else if ((BC == BC_EQ && E->Num == 0)             ||
657                        (BC == BC_NE && E->Num != 0)             ||
658                        (BC == BC_PL && (E->Num & 0x80) == 0)    ||
659                        (BC == BC_MI && (E->Num & 0x80) != 0)) {
660
661                 /* The branch is always taken, replace it by a jump */
662                 CE_ReplaceOPC (N, OP65_JMP);
663
664                 /* Remember, we had changes */
665                 ++Changes;
666             }
667
668         }
669
670         if ((E->Info & OF_CBRA) != 0              &&  /* It's a conditional branch */
671             (L = E->JumpTo) != 0                  &&  /* ..referencing a local label */
672             (N = CS_GetNextEntry (S, I)) != 0     &&  /* There is a following entry */
673             (N->Info & OF_UBRA) != 0              &&  /* ..which is an uncond branch, */
674             !CE_HasLabel (N)                      &&  /* ..has no label attached */
675             L->Owner == CS_GetNextEntry (S, I+1)) {/* ..and jump target follows */
676
677             /* Replace the jump by a conditional branch with the inverse branch
678              * condition than the branch around it.
679              */
680             CE_ReplaceOPC (N, GetInverseBranch (E->OPC));
681
682             /* Remove the conditional branch */
683             CS_DelEntry (S, I);
684
685             /* Remember, we had changes */
686             ++Changes;
687
688         }
689
690         /* Next entry */
691         ++I;
692
693     }
694
695     /* Return the number of changes made */
696     return Changes;
697 }
698
699
700
701 /*****************************************************************************/
702 /*                      Remove unused loads and stores                       */
703 /*****************************************************************************/
704
705
706
707 unsigned OptUnusedLoads (CodeSeg* S)
708 /* Remove loads of registers where the value loaded is not used later. */
709 {
710     unsigned Changes = 0;
711
712     /* Walk over the entries */
713     unsigned I = 0;
714     while (I < CS_GetEntryCount (S)) {
715
716         CodeEntry* N;
717
718         /* Get next entry */
719         CodeEntry* E = CS_GetEntry (S, I);
720
721         /* Check if it's a register load or transfer insn */
722         if ((E->Info & (OF_LOAD | OF_XFR | OF_REG_INCDEC)) != 0         &&
723             (N = CS_GetNextEntry (S, I)) != 0                           &&
724             !CE_UseLoadFlags (N)) {
725
726             /* Check which sort of load or transfer it is */
727             unsigned R;
728             switch (E->OPC) {
729                 case OP65_DEA:
730                 case OP65_INA:
731                 case OP65_LDA:
732                 case OP65_TXA:
733                 case OP65_TYA:  R = REG_A;      break;
734                 case OP65_DEX:
735                 case OP65_INX:
736                 case OP65_LDX:
737                 case OP65_TAX:  R = REG_X;      break;
738                 case OP65_DEY:
739                 case OP65_INY:
740                 case OP65_LDY:
741                 case OP65_TAY:  R = REG_Y;      break;
742                 default:        goto NextEntry;         /* OOPS */
743             }
744
745             /* Get register usage and check if the register value is used later */
746             if ((GetRegInfo (S, I+1, R) & R) == 0) {
747
748                 /* Register value is not used, remove the load */
749                 CS_DelEntry (S, I);
750
751                 /* Remember, we had changes. Account the deleted entry in I. */
752                 ++Changes;
753                 --I;
754
755             }
756         }
757
758 NextEntry:
759         /* Next entry */
760         ++I;
761
762     }
763
764     /* Return the number of changes made */
765     return Changes;
766 }
767
768
769
770 unsigned OptUnusedStores (CodeSeg* S)
771 /* Remove stores into zero page registers that aren't used later */
772 {
773     unsigned Changes = 0;
774
775     /* Walk over the entries */
776     unsigned I = 0;
777     while (I < CS_GetEntryCount (S)) {
778
779         /* Get next entry */
780         CodeEntry* E = CS_GetEntry (S, I);
781
782         /* Check if it's a register load or transfer insn */
783         if ((E->Info & OF_STORE) != 0    &&
784             E->AM == AM65_ZP             &&
785             (E->Chg & REG_ZP) != 0) {
786
787             /* Check for the zero page location. We know that there cannot be
788              * more than one zero page location involved in the store.
789              */
790             unsigned R = E->Chg & REG_ZP;
791
792             /* Get register usage and check if the register value is used later */
793             if ((GetRegInfo (S, I+1, R) & R) == 0) {
794
795                 /* Register value is not used, remove the load */
796                 CS_DelEntry (S, I);
797
798                 /* Remember, we had changes */
799                 ++Changes;
800
801             }
802         }
803
804         /* Next entry */
805         ++I;
806
807     }
808
809     /* Return the number of changes made */
810     return Changes;
811 }
812
813
814
815 unsigned OptDupLoads (CodeSeg* S)
816 /* Remove loads of registers where the value loaded is already in the register. */
817 {
818     unsigned Changes = 0;
819     unsigned I;
820
821     /* Generate register info for this step */
822     CS_GenRegInfo (S);
823
824     /* Walk over the entries */
825     I = 0;
826     while (I < CS_GetEntryCount (S)) {
827
828         CodeEntry* N;
829
830         /* Get next entry */
831         CodeEntry* E = CS_GetEntry (S, I);
832
833         /* Assume we won't delete the entry */
834         int Delete = 0;
835
836         /* Get a pointer to the input registers of the insn */
837         const RegContents* In  = &E->RI->In;
838
839         /* Handle the different instructions */
840         switch (E->OPC) {
841
842             case OP65_LDA:
843                 if (RegValIsKnown (In->RegA)          && /* Value of A is known */
844                     CE_IsKnownImm (E, In->RegA)       && /* Value to be loaded is known */
845                     (N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */
846                     !CE_UseLoadFlags (N)) {              /* Which does not use the flags */
847                     Delete = 1;
848                 }
849                 break;
850
851             case OP65_LDX:
852                 if (RegValIsKnown (In->RegX)          && /* Value of X is known */
853                     CE_IsKnownImm (E, In->RegX)       && /* Value to be loaded is known */
854                     (N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */
855                     !CE_UseLoadFlags (N)) {              /* Which does not use the flags */
856                     Delete = 1;
857                 }
858                 break;
859
860             case OP65_LDY:
861                 if (RegValIsKnown (In->RegY)          && /* Value of Y is known */
862                     CE_IsKnownImm (E, In->RegY)       && /* Value to be loaded is known */
863                     (N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */
864                     !CE_UseLoadFlags (N)) {              /* Which does not use the flags */
865                     Delete = 1;
866                 }
867                 break;
868
869             case OP65_STA:
870                 /* If we store into a known zero page location, and this
871                  * location does already contain the value to be stored,
872                  * remove the store.
873                  */
874                 if (RegValIsKnown (In->RegA)          && /* Value of A is known */
875                     E->AM == AM65_ZP                  && /* Store into zp */
876                     In->RegA == ZPRegVal (E->Chg, In)) { /* Value identical */
877
878                     Delete = 1;
879                 }
880                 break;
881
882             case OP65_STX:
883                 /* If we store into a known zero page location, and this
884                  * location does already contain the value to be stored,
885                  * remove the store.
886                  */
887                 if (RegValIsKnown (In->RegX)          && /* Value of A is known */
888                     E->AM == AM65_ZP                  && /* Store into zp */
889                     In->RegX == ZPRegVal (E->Chg, In)) { /* Value identical */
890
891                     Delete = 1;
892
893                 /* If the value in the X register is known and the same as
894                  * that in the A register, replace the store by a STA. The
895                  * optimizer will then remove the load instruction for X
896                  * later. STX does support the zeropage,y addressing mode,
897                  * so be sure to check for that.
898                  */
899                 } else if (RegValIsKnown (In->RegX)   &&
900                            In->RegX == In->RegA       &&
901                            E->AM != AM65_ABSY         &&
902                            E->AM != AM65_ZPY) {
903                     /* Use the A register instead */
904                     CE_ReplaceOPC (E, OP65_STA);
905                 }
906                 break;
907
908             case OP65_STY:
909                 /* If we store into a known zero page location, and this
910                  * location does already contain the value to be stored,
911                  * remove the store.
912                  */
913                 if (RegValIsKnown (In->RegY)          && /* Value of Y is known */
914                     E->AM == AM65_ZP                  && /* Store into zp */
915                     In->RegY == ZPRegVal (E->Chg, In)) { /* Value identical */
916
917                     Delete = 1;
918
919                 /* If the value in the Y register is known and the same as
920                  * that in the A register, replace the store by a STA. The
921                  * optimizer will then remove the load instruction for Y
922                  * later. If replacement by A is not possible try a
923                  * replacement by X, but check for invalid addressing modes
924                  * in this case.
925                  */
926                 } else if (RegValIsKnown (In->RegY)) {
927                     if (In->RegY == In->RegA) {
928                         CE_ReplaceOPC (E, OP65_STA);
929                     } else if (In->RegY == In->RegX   &&
930                                E->AM != AM65_ABSX     &&
931                                E->AM != AM65_ZPX) {
932                         CE_ReplaceOPC (E, OP65_STX);
933                     }
934                 }
935                 break;
936
937             case OP65_STZ:
938                 /* If we store into a known zero page location, and this
939                  * location does already contain the value to be stored,
940                  * remove the store.
941                  */
942                 if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && E->AM == AM65_ZP) {
943                     if (ZPRegVal (E->Chg, In) == 0) {
944                         Delete = 1;
945                     }
946                 }
947                 break;
948
949             case OP65_TAX:
950                 if (RegValIsKnown (In->RegA)          &&
951                     In->RegA == In->RegX              &&
952                     (N = CS_GetNextEntry (S, I)) != 0 &&
953                     !CE_UseLoadFlags (N)) {
954                     /* Value is identical and not followed by a branch */
955                     Delete = 1;
956                 }
957                 break;
958
959             case OP65_TAY:
960                 if (RegValIsKnown (In->RegA)            &&
961                     In->RegA == In->RegY                &&
962                     (N = CS_GetNextEntry (S, I)) != 0   &&
963                     !CE_UseLoadFlags (N)) {
964                     /* Value is identical and not followed by a branch */
965                     Delete = 1;
966                 }
967                 break;
968
969             case OP65_TXA:
970                 if (RegValIsKnown (In->RegX)            &&
971                     In->RegX == In->RegA                &&
972                     (N = CS_GetNextEntry (S, I)) != 0   &&
973                     !CE_UseLoadFlags (N)) {
974                     /* Value is identical and not followed by a branch */
975                     Delete = 1;
976                 }
977                 break;
978
979             case OP65_TYA:
980                 if (RegValIsKnown (In->RegY)            &&
981                     In->RegY == In->RegA                &&
982                     (N = CS_GetNextEntry (S, I)) != 0   &&
983                     !CE_UseLoadFlags (N)) {
984                     /* Value is identical and not followed by a branch */
985                     Delete = 1;
986                 }
987                 break;
988
989             default:
990                 break;
991
992         }
993
994         /* Delete the entry if requested */
995         if (Delete) {
996
997             /* Register value is not used, remove the load */
998             CS_DelEntry (S, I);
999
1000             /* Remember, we had changes */
1001             ++Changes;
1002
1003         } else {
1004
1005             /* Next entry */
1006             ++I;
1007
1008         }
1009
1010     }
1011
1012     /* Free register info */
1013     CS_FreeRegInfo (S);
1014
1015     /* Return the number of changes made */
1016     return Changes;
1017 }
1018
1019
1020
1021 unsigned OptStoreLoad (CodeSeg* S)
1022 /* Remove a store followed by a load from the same location. */
1023 {
1024     unsigned Changes = 0;
1025
1026     /* Walk over the entries */
1027     unsigned I = 0;
1028     while (I < CS_GetEntryCount (S)) {
1029
1030         CodeEntry* N;
1031         CodeEntry* X;
1032
1033         /* Get next entry */
1034         CodeEntry* E = CS_GetEntry (S, I);
1035
1036         /* Check if it is a store instruction followed by a load from the
1037          * same address which is itself not followed by a conditional branch.
1038          */
1039         if ((E->Info & OF_STORE) != 0                       &&
1040             (N = CS_GetNextEntry (S, I)) != 0               &&
1041             !CE_HasLabel (N)                                &&
1042             E->AM == N->AM                                  &&
1043             ((E->OPC == OP65_STA && N->OPC == OP65_LDA) ||
1044              (E->OPC == OP65_STX && N->OPC == OP65_LDX) ||
1045              (E->OPC == OP65_STY && N->OPC == OP65_LDY))    &&
1046             strcmp (E->Arg, N->Arg) == 0                    &&
1047             (X = CS_GetNextEntry (S, I+1)) != 0             &&
1048             !CE_UseLoadFlags (X)) {
1049
1050             /* Register has already the correct value, remove the load */
1051             CS_DelEntry (S, I+1);
1052
1053             /* Remember, we had changes */
1054             ++Changes;
1055
1056         }
1057
1058         /* Next entry */
1059         ++I;
1060
1061     }
1062
1063     /* Return the number of changes made */
1064     return Changes;
1065 }
1066
1067
1068
1069 unsigned OptTransfers1 (CodeSeg* S)
1070 /* Remove transfers from one register to another and back */
1071 {
1072     unsigned Changes = 0;
1073
1074     /* Walk over the entries */
1075     unsigned I = 0;
1076     while (I < CS_GetEntryCount (S)) {
1077
1078         CodeEntry* N;
1079         CodeEntry* X;
1080         CodeEntry* P;
1081
1082         /* Get next entry */
1083         CodeEntry* E = CS_GetEntry (S, I);
1084
1085         /* Check if we have two transfer instructions */
1086         if ((E->Info & OF_XFR) != 0                 &&
1087             (N = CS_GetNextEntry (S, I)) != 0       &&
1088             !CE_HasLabel (N)                        &&
1089             (N->Info & OF_XFR) != 0) {
1090
1091             /* Check if it's a transfer and back */
1092             if ((E->OPC == OP65_TAX && N->OPC == OP65_TXA && !RegXUsed (S, I+2)) ||
1093                 (E->OPC == OP65_TAY && N->OPC == OP65_TYA && !RegYUsed (S, I+2)) ||
1094                 (E->OPC == OP65_TXA && N->OPC == OP65_TAX && !RegAUsed (S, I+2)) ||
1095                 (E->OPC == OP65_TYA && N->OPC == OP65_TAY && !RegAUsed (S, I+2))) {
1096
1097                 /* If the next insn is a conditional branch, check if the insn
1098                  * preceeding the first xfr will set the flags right, otherwise we
1099                  * may not remove the sequence.
1100                  */
1101                 if ((X = CS_GetNextEntry (S, I+1)) == 0) {
1102                     goto NextEntry;
1103                 }
1104                 if (CE_UseLoadFlags (X)) {
1105                     if (I == 0) {
1106                         /* No preceeding entry */
1107                         goto NextEntry;
1108                     }
1109                     P = CS_GetEntry (S, I-1);
1110                     if ((P->Info & OF_SETF) == 0) {
1111                         /* Does not set the flags */
1112                         goto NextEntry;
1113                     }
1114                 }
1115
1116                 /* Remove both transfers */
1117                 CS_DelEntry (S, I+1);
1118                 CS_DelEntry (S, I);
1119
1120                 /* Remember, we had changes */
1121                 ++Changes;
1122             }
1123         }
1124
1125 NextEntry:
1126         /* Next entry */
1127         ++I;
1128
1129     }
1130
1131     /* Return the number of changes made */
1132     return Changes;
1133 }
1134
1135
1136
1137 unsigned OptTransfers2 (CodeSeg* S)
1138 /* Replace loads followed by a register transfer by a load with the second
1139  * register if possible.
1140  */
1141 {
1142     unsigned Changes = 0;
1143
1144     /* Walk over the entries */
1145     unsigned I = 0;
1146     while (I < CS_GetEntryCount (S)) {
1147
1148         CodeEntry* N;
1149
1150         /* Get next entry */
1151         CodeEntry* E = CS_GetEntry (S, I);
1152
1153         /* Check if we have a load followed by a transfer where the loaded
1154          * register is not used later.
1155          */
1156         if ((E->Info & OF_LOAD) != 0                &&
1157             (N = CS_GetNextEntry (S, I)) != 0       &&
1158             !CE_HasLabel (N)                        &&
1159             (N->Info & OF_XFR) != 0                 &&
1160             GetRegInfo (S, I+2, E->Chg) != E->Chg) {
1161
1162             CodeEntry* X = 0;
1163
1164             if (E->OPC == OP65_LDA && N->OPC == OP65_TAX) {
1165                 /* LDA/TAX - check for the right addressing modes */
1166                 if (E->AM == AM65_IMM ||
1167                     E->AM == AM65_ZP  ||
1168                     E->AM == AM65_ABS ||
1169                     E->AM == AM65_ABSY) {
1170                     /* Replace */
1171                     X = NewCodeEntry (OP65_LDX, E->AM, E->Arg, 0, N->LI);
1172                 }
1173             } else if (E->OPC == OP65_LDA && N->OPC == OP65_TAY) {
1174                 /* LDA/TAY - check for the right addressing modes */
1175                 if (E->AM == AM65_IMM ||
1176                     E->AM == AM65_ZP  ||
1177                     E->AM == AM65_ZPX ||
1178                     E->AM == AM65_ABS ||
1179                     E->AM == AM65_ABSX) {
1180                     /* Replace */
1181                     X = NewCodeEntry (OP65_LDY, E->AM, E->Arg, 0, N->LI);
1182                 }
1183             } else if (E->OPC == OP65_LDY && N->OPC == OP65_TYA) {
1184                 /* LDY/TYA. LDA supports all addressing modes LDY does */
1185                 X = NewCodeEntry (OP65_LDA, E->AM, E->Arg, 0, N->LI);
1186             } else if (E->OPC == OP65_LDX && N->OPC == OP65_TXA) {
1187                 /* LDX/TXA. LDA doesn't support zp,y, so we must map it to
1188                  * abs,y instead.
1189                  */
1190                 am_t AM = (E->AM == AM65_ZPY)? AM65_ABSY : E->AM;
1191                 X = NewCodeEntry (OP65_LDA, AM, E->Arg, 0, N->LI);
1192             }
1193
1194             /* If we have a load entry, add it and remove the old stuff */
1195             if (X) {
1196                 CS_InsertEntry (S, X, I+2);
1197                 CS_DelEntries (S, I, 2);
1198                 ++Changes;
1199                 --I;    /* Correct for one entry less */
1200             }
1201         }
1202
1203         /* Next entry */
1204         ++I;
1205     }
1206
1207     /* Return the number of changes made */
1208     return Changes;
1209 }
1210
1211
1212
1213 unsigned OptPushPop (CodeSeg* S)
1214 /* Remove a PHA/PLA sequence were A is not used later */
1215 {
1216     unsigned Changes = 0;
1217     unsigned Push    = 0;       /* Index of push insn */
1218     unsigned Pop     = 0;       /* Index of pop insn */
1219     enum {
1220         Searching,
1221         FoundPush,
1222         FoundPop
1223     } State = Searching;
1224
1225     /* Walk over the entries. Look for a push instruction that is followed by
1226      * a pop later, where the pop is not followed by an conditional branch,
1227      * and where the value of the A register is not used later on.
1228      * Look out for the following problems:
1229      *
1230      *  - There may be another PHA/PLA inside the sequence: Restart it.
1231      *  - If the PLA has a label, all jumps to this label must be inside
1232      *    the sequence, otherwise we cannot remove the PHA/PLA.
1233      */
1234     unsigned I = 0;
1235     while (I < CS_GetEntryCount (S)) {
1236
1237         /* Get next entry */
1238         CodeEntry* E = CS_GetEntry (S, I);
1239
1240         switch (State) {
1241
1242             case Searching:
1243                 if (E->OPC == OP65_PHA) {
1244                     /* Found start of sequence */
1245                     Push  = I;
1246                     State = FoundPush;
1247                 }
1248                 break;
1249
1250             case FoundPush:
1251                 if (E->OPC == OP65_PHA) {
1252                     /* Inner push/pop, restart */
1253                     Push = I;
1254                 } else if (E->OPC == OP65_PLA) {
1255                     /* Found a matching pop */
1256                     Pop = I;
1257                     State = FoundPop;
1258                 }
1259                 break;
1260
1261             case FoundPop:
1262                 /* Next insn, just check if it is no conditional branch and
1263                  * that A is not used later. Check also that the range we have
1264                  * found now is a basic block, which means that the PHA is the
1265                  * only entrance and the PLA the only exit.
1266                  */
1267                 if ((E->Info & OF_CBRA) == 0    &&
1268                     !RegAUsed (S, I)            &&
1269                     CS_IsBasicBlock (S, Push, Pop)) {
1270                     /* We can remove the PHA and PLA instructions */
1271                     CS_DelEntry (S, Pop);
1272                     CS_DelEntry (S, Push);
1273                     /* Correct I so we continue with the next insn */
1274                     I -= 2;
1275                     /* Remember we had changes */
1276                     ++Changes;
1277                 }
1278                 /* Go into search mode again */
1279                 State = Searching;
1280                 break;
1281
1282         }
1283
1284         /* Next entry */
1285         ++I;
1286     }
1287
1288     /* Return the number of changes made */
1289     return Changes;
1290 }
1291
1292
1293
1294 unsigned OptPrecalc (CodeSeg* S)
1295 /* Replace immediate operations with the accu where the current contents are
1296  * known by a load of the final value.
1297  */
1298 {
1299     unsigned Changes = 0;
1300     unsigned I;
1301
1302     /* Generate register info for this step */
1303     CS_GenRegInfo (S);
1304
1305     /* Walk over the entries */
1306     I = 0;
1307     while (I < CS_GetEntryCount (S)) {
1308
1309         /* Get next entry */
1310         CodeEntry* E = CS_GetEntry (S, I);
1311
1312         /* Get a pointer to the output registers of the insn */
1313         const RegContents* Out = &E->RI->Out;
1314
1315         /* Argument for LDn and flag */
1316         const char* Arg = 0;
1317         opc_t OPC = OP65_LDA;
1318
1319         /* Handle the different instructions */
1320         switch (E->OPC) {
1321
1322             case OP65_LDA:
1323                 if (E->AM != AM65_IMM && RegValIsKnown (Out->RegA)) {
1324                     /* Result of load is known */
1325                     Arg = MakeHexArg (Out->RegA);
1326                 }
1327                 break;
1328
1329             case OP65_LDX:
1330                 if (E->AM != AM65_IMM && RegValIsKnown (Out->RegX)) {
1331                     /* Result of load is known but register is X */
1332                     Arg = MakeHexArg (Out->RegX);
1333                     OPC = OP65_LDX;
1334                 }
1335                 break;
1336
1337             case OP65_LDY:
1338                 if (E->AM != AM65_IMM && RegValIsKnown (Out->RegY)) {
1339                     /* Result of load is known but register is Y */
1340                     Arg = MakeHexArg (Out->RegY);
1341                     OPC = OP65_LDY;
1342                 }
1343                 break;
1344
1345             case OP65_ADC:
1346             case OP65_ASL:
1347             case OP65_EOR:
1348             case OP65_LSR:
1349             case OP65_SBC:
1350                 if (RegValIsKnown (Out->RegA)) {
1351                     /* Accu op zp with known contents */
1352                     Arg = MakeHexArg (Out->RegA);
1353                 }
1354                 break;
1355
1356             case OP65_AND:
1357                 if (CE_IsKnownImm (E, 0xFF)) {
1358                     /* AND with 0xFF, remove */
1359                     CS_DelEntry (S, I);
1360                     ++Changes;
1361                 } else if (RegValIsKnown (Out->RegA)) {
1362                     /* Accu AND zp with known contents */
1363                     Arg = MakeHexArg (Out->RegA);
1364                 }
1365                 break;
1366
1367             case OP65_ORA:
1368                 if (CE_IsKnownImm (E, 0x00)) {
1369                     /* ORA with zero, remove */
1370                     CS_DelEntry (S, I);
1371                     ++Changes;
1372                 } else if (RegValIsKnown (Out->RegA)) {
1373                     /* Accu AND zp with known contents */
1374                     Arg = MakeHexArg (Out->RegA);
1375                 }
1376                 break;
1377
1378             default:
1379                 break;
1380
1381         }
1382
1383         /* Check if we have to replace the insn by LDA */
1384         if (Arg) {
1385             CodeEntry* X = NewCodeEntry (OPC, AM65_IMM, Arg, 0, E->LI);
1386             CS_InsertEntry (S, X, I+1);
1387             CS_DelEntry (S, I);
1388             ++Changes;
1389         }
1390
1391         /* Next entry */
1392         ++I;
1393     }
1394
1395     /* Free register info */
1396     CS_FreeRegInfo (S);
1397
1398     /* Return the number of changes made */
1399     return Changes;
1400 }
1401
1402
1403
1404 /*****************************************************************************/
1405 /*                           Optimize branch types                           */
1406 /*****************************************************************************/
1407
1408
1409
1410 unsigned OptBranchDist (CodeSeg* S)
1411 /* Change branches for the distance needed. */
1412 {
1413     unsigned Changes = 0;
1414
1415     /* Walk over the entries */
1416     unsigned I = 0;
1417     while (I < CS_GetEntryCount (S)) {
1418
1419         /* Get next entry */
1420         CodeEntry* E = CS_GetEntry (S, I);
1421
1422         /* Check if it's a conditional branch to a local label. */
1423         if (E->Info & OF_CBRA) {
1424
1425             /* Is this a branch to a local symbol? */
1426             if (E->JumpTo != 0) {
1427
1428                 /* Check if the branch distance is short */
1429                 int IsShort = IsShortDist (GetBranchDist (S, I, E->JumpTo->Owner));
1430
1431                 /* Make the branch short/long according to distance */
1432                 if ((E->Info & OF_LBRA) == 0 && !IsShort) {
1433                     /* Short branch but long distance */
1434                     CE_ReplaceOPC (E, MakeLongBranch (E->OPC));
1435                     ++Changes;
1436                 } else if ((E->Info & OF_LBRA) != 0 && IsShort) {
1437                     /* Long branch but short distance */
1438                     CE_ReplaceOPC (E, MakeShortBranch (E->OPC));
1439                     ++Changes;
1440                 }
1441
1442             } else if ((E->Info & OF_LBRA) == 0) {
1443
1444                 /* Short branch to external symbol - make it long */
1445                 CE_ReplaceOPC (E, MakeLongBranch (E->OPC));
1446                 ++Changes;
1447
1448             }
1449
1450         } else if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 &&
1451                    (E->Info & OF_UBRA) != 0               &&
1452                    E->JumpTo != 0                         &&
1453                    IsShortDist (GetBranchDist (S, I, E->JumpTo->Owner))) {
1454
1455             /* The jump is short and may be replaced by a BRA on the 65C02 CPU */
1456             CE_ReplaceOPC (E, OP65_BRA);
1457             ++Changes;
1458         }
1459
1460         /* Next entry */
1461         ++I;
1462
1463     }
1464
1465     /* Return the number of changes made */
1466     return Changes;
1467 }
1468
1469
1470