]> git.sur5r.net Git - cc65/blob - src/cc65/coptind.c
Added HuC6280 cpu (will be treated as a 65C02)
[cc65] / src / cc65 / coptind.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 coptind.c                                 */
4 /*                                                                           */
5 /*              Environment independent low level optimizations              */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2001-2004 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             /* Check if both are conditional branches, and the condition of
410              * the second is the inverse of that of the first. In this case,
411              * the second branch will never be taken, and we may jump directly
412              * to the instruction behind this one.
413              */
414             } else if ((E->Info & OF_CBRA) != 0 && (N->Info & OF_CBRA) != 0) {
415
416                 CodeEntry* X;   /* Instruction behind N */
417                 CodeLabel* LX;  /* Label attached to X */
418
419                 /* Get the branch conditions of both branches */
420                 bc_t BC1 = GetBranchCond (E->OPC);
421                 bc_t BC2 = GetBranchCond (N->OPC);
422
423                 /* Check the branch conditions */
424                 if (BC1 != GetInverseCond (BC2)) {
425                     /* Condition not met */
426                     goto NextEntry;
427                 }
428
429                 /* We may jump behind this conditional branch. Get the
430                  * pointer to the next instruction
431                  */
432                 if ((X = CS_GetNextEntry (S, CS_GetEntryIndex (S, N))) == 0) {
433                     /* N is the last entry, bail out */
434                     goto NextEntry;
435                 }
436
437                 /* Get the label attached to X, create a new one if needed */
438                 LX = CS_GenLabel (S, X);
439
440                 /* Move the reference from E to the new label */
441                 CS_MoveLabelRef (S, E, LX);
442
443                 /* Remember, we had changes */
444                 ++Changes;
445
446             }
447         }
448
449 NextEntry:
450         /* Next entry */
451         ++I;
452
453     }
454
455     /* Return the number of changes made */
456     return Changes;
457 }
458
459
460
461 /*****************************************************************************/
462 /*                             Optimize jsr/rts                              */
463 /*****************************************************************************/
464
465
466
467 unsigned OptRTS (CodeSeg* S)
468 /* Optimize subroutine calls followed by an RTS. The subroutine call will get
469  * replaced by a jump. Don't bother to delete the RTS if it does not have a
470  * label, the dead code elimination should take care of it.
471  */
472 {
473     unsigned Changes = 0;
474
475     /* Walk over all entries minus the last one */
476     unsigned I = 0;
477     while (I < CS_GetEntryCount (S)) {
478
479         CodeEntry* N;
480
481         /* Get this entry */
482         CodeEntry* E = CS_GetEntry (S, I);
483
484         /* Check if it's a subroutine call and if the following insn is RTS */
485         if (E->OPC == OP65_JSR                    &&
486             (N = CS_GetNextEntry (S, I)) != 0 &&
487             N->OPC == OP65_RTS) {
488
489             /* Change the jsr to a jmp and use the additional info for a jump */
490             E->AM = AM65_BRA;
491             CE_ReplaceOPC (E, OP65_JMP);
492
493             /* Remember, we had changes */
494             ++Changes;
495
496         }
497
498         /* Next entry */
499         ++I;
500
501     }
502
503     /* Return the number of changes made */
504     return Changes;
505 }
506
507
508
509 /*****************************************************************************/
510 /*                           Optimize jump targets                           */
511 /*****************************************************************************/
512
513
514
515 unsigned OptJumpTarget (CodeSeg* S)
516 /* If the instruction preceeding an unconditional branch is the same as the
517  * instruction preceeding the jump target, the jump target may be moved
518  * one entry back. This is a size optimization, since the instruction before
519  * the branch gets removed.
520  */
521 {
522     unsigned Changes = 0;
523     CodeEntry* E1;              /* Entry 1 */
524     CodeEntry* E2;              /* Entry 2 */
525     CodeEntry* T1;              /* Jump target entry 1 */
526     CodeLabel* TL1;             /* Target label 1 */
527
528     /* Walk over the entries */
529     unsigned I = 0;
530     while (I < CS_GetEntryCount (S)) {
531
532         /* Get next entry */
533         E2 = CS_GetNextEntry (S, I);
534
535         /* Check if we have a jump or branch, and a matching label, which
536          * is not attached to the jump itself
537          */
538         if (E2 != 0                     &&
539             (E2->Info & OF_UBRA) != 0   &&
540             E2->JumpTo                  &&
541             E2->JumpTo->Owner != E2) {
542
543             /* Get the entry preceeding the branch target */
544             T1 = CS_GetPrevEntry (S, CS_GetEntryIndex (S, E2->JumpTo->Owner));
545             if (T1 == 0) {
546                 /* There is no such entry */
547                 goto NextEntry;
548             }
549
550             /* Get the entry preceeding the jump */
551             E1 = CS_GetEntry (S, I);
552
553             /* Check if both preceeding instructions are identical */
554             if (!CodeEntriesAreEqual (E1, T1)) {
555                 /* Not equal, try next */
556                 goto NextEntry;
557             }
558
559             /* Get the label for the instruction preceeding the jump target.
560              * This routine will create a new label if the instruction does
561              * not already have one.
562              */
563             TL1 = CS_GenLabel (S, T1);
564
565             /* Change the jump target to point to this new label */
566             CS_MoveLabelRef (S, E2, TL1);
567
568             /* If the instruction preceeding the jump has labels attached,
569              * move references to this label to the new label.
570              */
571             if (CE_HasLabel (E1)) {
572                 CS_MoveLabels (S, E1, T1);
573             }
574
575             /* Remove the entry preceeding the jump */
576             CS_DelEntry (S, I);
577
578             /* Remember, we had changes */
579             ++Changes;
580
581         } else {
582 NextEntry:
583             /* Next entry */
584             ++I;
585         }
586     }
587
588     /* Return the number of changes made */
589     return Changes;
590 }
591
592
593
594 /*****************************************************************************/
595 /*                       Optimize conditional branches                       */
596 /*****************************************************************************/
597
598
599
600 unsigned OptCondBranches (CodeSeg* S)
601 /* Performs several optimization steps:
602  *
603  *  - If an immidiate load of a register is followed by a conditional jump that
604  *    is never taken because the load of the register sets the flags in such a
605  *    manner, remove the conditional branch.
606  *  - If the conditional branch is always taken because of the register load,
607  *    replace it by a jmp.
608  *  - If a conditional branch jumps around an unconditional branch, remove the
609  *    conditional branch and make the jump a conditional branch with the
610  *    inverse condition of the first one.
611  */
612 {
613     unsigned Changes = 0;
614
615     /* Walk over the entries */
616     unsigned I = 0;
617     while (I < CS_GetEntryCount (S)) {
618
619         CodeEntry* N;
620         CodeLabel* L;
621
622         /* Get next entry */
623         CodeEntry* E = CS_GetEntry (S, I);
624
625         /* Check if it's a register load */
626         if ((E->Info & OF_LOAD) != 0              &&  /* It's a load instruction */
627             E->AM == AM65_IMM                     &&  /* ..with immidiate addressing */
628             (E->Flags & CEF_NUMARG) != 0          &&  /* ..and a numeric argument. */
629             (N = CS_GetNextEntry (S, I)) != 0     &&  /* There is a following entry */
630             (N->Info & OF_CBRA) != 0              &&  /* ..which is a conditional branch */
631             !CE_HasLabel (N)) {               /* ..and does not have a label */
632
633             /* Get the branch condition */
634             bc_t BC = GetBranchCond (N->OPC);
635
636             /* Check the argument against the branch condition */
637             if ((BC == BC_EQ && E->Num != 0)            ||
638                 (BC == BC_NE && E->Num == 0)            ||
639                 (BC == BC_PL && (E->Num & 0x80) != 0)   ||
640                 (BC == BC_MI && (E->Num & 0x80) == 0)) {
641
642                 /* Remove the conditional branch */
643                 CS_DelEntry (S, I+1);
644
645                 /* Remember, we had changes */
646                 ++Changes;
647
648             } else if ((BC == BC_EQ && E->Num == 0)             ||
649                        (BC == BC_NE && E->Num != 0)             ||
650                        (BC == BC_PL && (E->Num & 0x80) == 0)    ||
651                        (BC == BC_MI && (E->Num & 0x80) != 0)) {
652
653                 /* The branch is always taken, replace it by a jump */
654                 CE_ReplaceOPC (N, OP65_JMP);
655
656                 /* Remember, we had changes */
657                 ++Changes;
658             }
659
660         }
661
662         if ((E->Info & OF_CBRA) != 0              &&  /* It's a conditional branch */
663             (L = E->JumpTo) != 0                  &&  /* ..referencing a local label */
664             (N = CS_GetNextEntry (S, I)) != 0     &&  /* There is a following entry */
665             (N->Info & OF_UBRA) != 0              &&  /* ..which is an uncond branch, */
666             !CE_HasLabel (N)                      &&  /* ..has no label attached */
667             L->Owner == CS_GetNextEntry (S, I+1)) {/* ..and jump target follows */
668
669             /* Replace the jump by a conditional branch with the inverse branch
670              * condition than the branch around it.
671              */
672             CE_ReplaceOPC (N, GetInverseBranch (E->OPC));
673
674             /* Remove the conditional branch */
675             CS_DelEntry (S, I);
676
677             /* Remember, we had changes */
678             ++Changes;
679
680         }
681
682         /* Next entry */
683         ++I;
684
685     }
686
687     /* Return the number of changes made */
688     return Changes;
689 }
690
691
692
693 /*****************************************************************************/
694 /*                      Remove unused loads and stores                       */
695 /*****************************************************************************/
696
697
698
699 unsigned OptUnusedLoads (CodeSeg* S)
700 /* Remove loads of registers where the value loaded is not used later. */
701 {
702     unsigned Changes = 0;
703
704     /* Walk over the entries */
705     unsigned I = 0;
706     while (I < CS_GetEntryCount (S)) {
707
708         CodeEntry* N;
709
710         /* Get next entry */
711         CodeEntry* E = CS_GetEntry (S, I);
712
713         /* Check if it's a register load or transfer insn */
714         if ((E->Info & (OF_LOAD | OF_XFR | OF_REG_INCDEC)) != 0         &&
715             (N = CS_GetNextEntry (S, I)) != 0                           &&
716             !CE_UseLoadFlags (N)) {
717
718             /* Check which sort of load or transfer it is */
719             unsigned R;
720             switch (E->OPC) {
721                 case OP65_DEA:
722                 case OP65_INA:
723                 case OP65_LDA:
724                 case OP65_TXA:
725                 case OP65_TYA:  R = REG_A;      break;
726                 case OP65_DEX:
727                 case OP65_INX:
728                 case OP65_LDX:
729                 case OP65_TAX:  R = REG_X;      break;
730                 case OP65_DEY:
731                 case OP65_INY:
732                 case OP65_LDY:
733                 case OP65_TAY:  R = REG_Y;      break;
734                 default:        goto NextEntry;         /* OOPS */
735             }
736
737             /* Get register usage and check if the register value is used later */
738             if ((GetRegInfo (S, I+1, R) & R) == 0) {
739
740                 /* Register value is not used, remove the load */
741                 CS_DelEntry (S, I);
742
743                 /* Remember, we had changes. Account the deleted entry in I. */
744                 ++Changes;
745                 --I;
746
747             }
748         }
749
750 NextEntry:
751         /* Next entry */
752         ++I;
753
754     }
755
756     /* Return the number of changes made */
757     return Changes;
758 }
759
760
761
762 unsigned OptUnusedStores (CodeSeg* S)
763 /* Remove stores into zero page registers that aren't used later */
764 {
765     unsigned Changes = 0;
766
767     /* Walk over the entries */
768     unsigned I = 0;
769     while (I < CS_GetEntryCount (S)) {
770
771         /* Get next entry */
772         CodeEntry* E = CS_GetEntry (S, I);
773
774         /* Check if it's a register load or transfer insn */
775         if ((E->Info & OF_STORE) != 0    &&
776             E->AM == AM65_ZP             &&
777             (E->Chg & REG_ZP) != 0) {
778
779             /* Check for the zero page location. We know that there cannot be
780              * more than one zero page location involved in the store.
781              */
782             unsigned R = E->Chg & REG_ZP;
783
784             /* Get register usage and check if the register value is used later */
785             if ((GetRegInfo (S, I+1, R) & R) == 0) {
786
787                 /* Register value is not used, remove the load */
788                 CS_DelEntry (S, I);
789
790                 /* Remember, we had changes */
791                 ++Changes;
792
793             }
794         }
795
796         /* Next entry */
797         ++I;
798
799     }
800
801     /* Return the number of changes made */
802     return Changes;
803 }
804
805
806
807 unsigned OptDupLoads (CodeSeg* S)
808 /* Remove loads of registers where the value loaded is already in the register. */
809 {
810     unsigned Changes = 0;
811     unsigned I;
812
813     /* Generate register info for this step */
814     CS_GenRegInfo (S);
815
816     /* Walk over the entries */
817     I = 0;
818     while (I < CS_GetEntryCount (S)) {
819
820         CodeEntry* N;
821
822         /* Get next entry */
823         CodeEntry* E = CS_GetEntry (S, I);
824
825         /* Assume we won't delete the entry */
826         int Delete = 0;
827
828         /* Get a pointer to the input registers of the insn */
829         const RegContents* In  = &E->RI->In;
830
831         /* Handle the different instructions */
832         switch (E->OPC) {
833
834             case OP65_LDA:
835                 if (RegValIsKnown (In->RegA)          && /* Value of A is known */
836                     CE_KnownImm (E)                   && /* Value to be loaded is known */
837                     In->RegA == (long) E->Num         && /* Both are equal */
838                     (N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */
839                     !CE_UseLoadFlags (N)) {              /* Which does not use the flags */
840                     Delete = 1;
841                 }
842                 break;
843
844             case OP65_LDX:
845                 if (RegValIsKnown (In->RegX)          && /* Value of X is known */
846                     CE_KnownImm (E)                   && /* Value to be loaded is known */
847                     In->RegX == (long) E->Num         && /* Both are equal */
848                     (N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */
849                     !CE_UseLoadFlags (N)) {              /* Which does not use the flags */
850                     Delete = 1;
851                 }
852                 break;
853
854             case OP65_LDY:
855                 if (RegValIsKnown (In->RegY)          && /* Value of Y is known */
856                     CE_KnownImm (E)                   && /* Value to be loaded is known */
857                     In->RegY == (long) E->Num         && /* Both are equal */
858                     (N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */
859                     !CE_UseLoadFlags (N)) {              /* Which does not use the flags */
860                     Delete = 1;
861                 }
862                 break;
863
864             case OP65_STA:
865                 /* If we store into a known zero page location, and this
866                  * location does already contain the value to be stored,
867                  * remove the store.
868                  */
869                 if (RegValIsKnown (In->RegA)          && /* Value of A is known */
870                     E->AM == AM65_ZP                  && /* Store into zp */
871                     In->RegA == ZPRegVal (E->Chg, In)) { /* Value identical */
872
873                     Delete = 1;
874                 }
875                 break;
876
877             case OP65_STX:
878                 /* If we store into a known zero page location, and this
879                  * location does already contain the value to be stored,
880                  * remove the store.
881                  */
882                 if (RegValIsKnown (In->RegX)          && /* Value of A is known */
883                     E->AM == AM65_ZP                  && /* Store into zp */
884                     In->RegX == ZPRegVal (E->Chg, In)) { /* Value identical */
885
886                     Delete = 1;
887
888                 /* If the value in the X register is known and the same as
889                  * that in the A register, replace the store by a STA. The
890                  * optimizer will then remove the load instruction for X
891                  * later. STX does support the zeropage,y addressing mode,
892                  * so be sure to check for that.
893                  */
894                 } else if (RegValIsKnown (In->RegX)   &&
895                            In->RegX == In->RegA       &&
896                            E->AM != AM65_ABSY         &&
897                            E->AM != AM65_ZPY) {
898                     /* Use the A register instead */
899                     CE_ReplaceOPC (E, OP65_STA);
900                 }
901                 break;
902
903             case OP65_STY:
904                 /* If we store into a known zero page location, and this
905                  * location does already contain the value to be stored,
906                  * remove the store.
907                  */
908                 if (RegValIsKnown (In->RegY)          && /* Value of Y is known */
909                     E->AM == AM65_ZP                  && /* Store into zp */
910                     In->RegY == ZPRegVal (E->Chg, In)) { /* Value identical */
911
912                     Delete = 1;
913
914                 /* If the value in the Y register is known and the same as
915                  * that in the A register, replace the store by a STA. The
916                  * optimizer will then remove the load instruction for Y
917                  * later. If replacement by A is not possible try a
918                  * replacement by X, but check for invalid addressing modes
919                  * in this case.
920                  */
921                 } else if (RegValIsKnown (In->RegY)) {
922                     if (In->RegY == In->RegA) {
923                         CE_ReplaceOPC (E, OP65_STA);
924                     } else if (In->RegY == In->RegX   &&
925                                E->AM != AM65_ABSX     &&
926                                E->AM != AM65_ZPX) {
927                         CE_ReplaceOPC (E, OP65_STX);
928                     }
929                 }
930                 break;
931
932             case OP65_STZ:
933                 /* If we store into a known zero page location, and this
934                  * location does already contain the value to be stored,
935                  * remove the store.
936                  */
937                 if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 && E->AM == AM65_ZP) {
938                     if (ZPRegVal (E->Chg, In) == 0) {
939                         Delete = 1;
940                     }
941                 }
942                 break;
943
944             case OP65_TAX:
945                 if (RegValIsKnown (In->RegA)          &&
946                     In->RegA == In->RegX              &&
947                     (N = CS_GetNextEntry (S, I)) != 0 &&
948                     !CE_UseLoadFlags (N)) {
949                     /* Value is identical and not followed by a branch */
950                     Delete = 1;
951                 }
952                 break;
953
954             case OP65_TAY:
955                 if (RegValIsKnown (In->RegA)            &&
956                     In->RegA == In->RegY                &&
957                     (N = CS_GetNextEntry (S, I)) != 0   &&
958                     !CE_UseLoadFlags (N)) {
959                     /* Value is identical and not followed by a branch */
960                     Delete = 1;
961                 }
962                 break;
963
964             case OP65_TXA:
965                 if (RegValIsKnown (In->RegX)            &&
966                     In->RegX == In->RegA                &&
967                     (N = CS_GetNextEntry (S, I)) != 0   &&
968                     !CE_UseLoadFlags (N)) {
969                     /* Value is identical and not followed by a branch */
970                     Delete = 1;
971                 }
972                 break;
973
974             case OP65_TYA:
975                 if (RegValIsKnown (In->RegY)            &&
976                     In->RegY == In->RegA                &&
977                     (N = CS_GetNextEntry (S, I)) != 0   &&
978                     !CE_UseLoadFlags (N)) {
979                     /* Value is identical and not followed by a branch */
980                     Delete = 1;
981                 }
982                 break;
983
984             default:
985                 break;
986
987         }
988
989         /* Delete the entry if requested */
990         if (Delete) {
991
992             /* Register value is not used, remove the load */
993             CS_DelEntry (S, I);
994
995             /* Remember, we had changes */
996             ++Changes;
997
998         } else {
999
1000             /* Next entry */
1001             ++I;
1002
1003         }
1004
1005     }
1006
1007     /* Free register info */
1008     CS_FreeRegInfo (S);
1009
1010     /* Return the number of changes made */
1011     return Changes;
1012 }
1013
1014
1015
1016 unsigned OptStoreLoad (CodeSeg* S)
1017 /* Remove a store followed by a load from the same location. */
1018 {
1019     unsigned Changes = 0;
1020
1021     /* Walk over the entries */
1022     unsigned I = 0;
1023     while (I < CS_GetEntryCount (S)) {
1024
1025         CodeEntry* N;
1026         CodeEntry* X;
1027
1028         /* Get next entry */
1029         CodeEntry* E = CS_GetEntry (S, I);
1030
1031         /* Check if it is a store instruction followed by a load from the
1032          * same address which is itself not followed by a conditional branch.
1033          */
1034         if ((E->Info & OF_STORE) != 0                       &&
1035             (N = CS_GetNextEntry (S, I)) != 0               &&
1036             !CE_HasLabel (N)                                &&
1037             E->AM == N->AM                                  &&
1038             ((E->OPC == OP65_STA && N->OPC == OP65_LDA) ||
1039              (E->OPC == OP65_STX && N->OPC == OP65_LDX) ||
1040              (E->OPC == OP65_STY && N->OPC == OP65_LDY))    &&
1041             strcmp (E->Arg, N->Arg) == 0                    &&
1042             (X = CS_GetNextEntry (S, I+1)) != 0             &&
1043             !CE_UseLoadFlags (X)) {
1044
1045             /* Register has already the correct value, remove the load */
1046             CS_DelEntry (S, I+1);
1047
1048             /* Remember, we had changes */
1049             ++Changes;
1050
1051         }
1052
1053         /* Next entry */
1054         ++I;
1055
1056     }
1057
1058     /* Return the number of changes made */
1059     return Changes;
1060 }
1061
1062
1063
1064 unsigned OptTransfers1 (CodeSeg* S)
1065 /* Remove transfers from one register to another and back */
1066 {
1067     unsigned Changes = 0;
1068
1069     /* Walk over the entries */
1070     unsigned I = 0;
1071     while (I < CS_GetEntryCount (S)) {
1072
1073         CodeEntry* N;
1074         CodeEntry* X;
1075         CodeEntry* P;
1076
1077         /* Get next entry */
1078         CodeEntry* E = CS_GetEntry (S, I);
1079
1080         /* Check if we have two transfer instructions */
1081         if ((E->Info & OF_XFR) != 0                 &&
1082             (N = CS_GetNextEntry (S, I)) != 0       &&
1083             !CE_HasLabel (N)                        &&
1084             (N->Info & OF_XFR) != 0) {
1085
1086             /* Check if it's a transfer and back */
1087             if ((E->OPC == OP65_TAX && N->OPC == OP65_TXA && !RegXUsed (S, I+2)) ||
1088                 (E->OPC == OP65_TAY && N->OPC == OP65_TYA && !RegYUsed (S, I+2)) ||
1089                 (E->OPC == OP65_TXA && N->OPC == OP65_TAX && !RegAUsed (S, I+2)) ||
1090                 (E->OPC == OP65_TYA && N->OPC == OP65_TAY && !RegAUsed (S, I+2))) {
1091
1092                 /* If the next insn is a conditional branch, check if the insn
1093                  * preceeding the first xfr will set the flags right, otherwise we
1094                  * may not remove the sequence.
1095                  */
1096                 if ((X = CS_GetNextEntry (S, I+1)) == 0) {
1097                     goto NextEntry;
1098                 }
1099                 if (CE_UseLoadFlags (X)) {
1100                     if (I == 0) {
1101                         /* No preceeding entry */
1102                         goto NextEntry;
1103                     }
1104                     P = CS_GetEntry (S, I-1);
1105                     if ((P->Info & OF_SETF) == 0) {
1106                         /* Does not set the flags */
1107                         goto NextEntry;
1108                     }
1109                 }
1110
1111                 /* Remove both transfers */
1112                 CS_DelEntry (S, I+1);
1113                 CS_DelEntry (S, I);
1114
1115                 /* Remember, we had changes */
1116                 ++Changes;
1117             }
1118         }
1119
1120 NextEntry:
1121         /* Next entry */
1122         ++I;
1123
1124     }
1125
1126     /* Return the number of changes made */
1127     return Changes;
1128 }
1129
1130
1131
1132 unsigned OptTransfers2 (CodeSeg* S)
1133 /* Replace loads followed by a register transfer by a load with the second
1134  * register if possible.
1135  */
1136 {
1137     unsigned Changes = 0;
1138
1139     /* Walk over the entries */
1140     unsigned I = 0;
1141     while (I < CS_GetEntryCount (S)) {
1142
1143         CodeEntry* N;
1144
1145         /* Get next entry */
1146         CodeEntry* E = CS_GetEntry (S, I);
1147
1148         /* Check if we have a load followed by a transfer where the loaded
1149          * register is not used later.
1150          */
1151         if ((E->Info & OF_LOAD) != 0                &&
1152             (N = CS_GetNextEntry (S, I)) != 0       &&
1153             !CE_HasLabel (N)                        &&
1154             (N->Info & OF_XFR) != 0                 &&
1155             GetRegInfo (S, I+2, E->Chg) != E->Chg) {
1156
1157             CodeEntry* X = 0;
1158
1159             if (E->OPC == OP65_LDA && N->OPC == OP65_TAX) {
1160                 /* LDA/TAX - check for the right addressing modes */
1161                 if (E->AM == AM65_IMM ||
1162                     E->AM == AM65_ZP  ||
1163                     E->AM == AM65_ABS ||
1164                     E->AM == AM65_ABSY) {
1165                     /* Replace */
1166                     X = NewCodeEntry (OP65_LDX, E->AM, E->Arg, 0, N->LI);
1167                 }
1168             } else if (E->OPC == OP65_LDA && N->OPC == OP65_TAY) {
1169                 /* LDA/TAY - check for the right addressing modes */
1170                 if (E->AM == AM65_IMM ||
1171                     E->AM == AM65_ZP  ||
1172                     E->AM == AM65_ZPX ||
1173                     E->AM == AM65_ABS ||
1174                     E->AM == AM65_ABSX) {
1175                     /* Replace */
1176                     X = NewCodeEntry (OP65_LDY, E->AM, E->Arg, 0, N->LI);
1177                 }
1178             } else if (E->OPC == OP65_LDY && N->OPC == OP65_TYA) {
1179                 /* LDY/TYA. LDA supports all addressing modes LDY does */
1180                 X = NewCodeEntry (OP65_LDA, E->AM, E->Arg, 0, N->LI);
1181             } else if (E->OPC == OP65_LDX && N->OPC == OP65_TXA) {
1182                 /* LDX/TXA. LDA doesn't support zp,y, so we must map it to
1183                  * abs,y instead.
1184                  */
1185                 am_t AM = (E->AM == AM65_ZPY)? AM65_ABSY : E->AM;
1186                 X = NewCodeEntry (OP65_LDA, AM, E->Arg, 0, N->LI);
1187             }
1188
1189             /* If we have a load entry, add it and remove the old stuff */
1190             if (X) {
1191                 CS_InsertEntry (S, X, I+2);
1192                 CS_DelEntries (S, I, 2);
1193                 ++Changes;
1194                 --I;    /* Correct for one entry less */
1195             }
1196         }
1197
1198         /* Next entry */
1199         ++I;
1200     }
1201
1202     /* Return the number of changes made */
1203     return Changes;
1204 }
1205
1206
1207
1208 unsigned OptPushPop (CodeSeg* S)
1209 /* Remove a PHA/PLA sequence were A is not used later */
1210 {
1211     unsigned Changes = 0;
1212     unsigned Push    = 0;       /* Index of push insn */
1213     unsigned Pop     = 0;       /* Index of pop insn */
1214     enum {
1215         Searching,
1216         FoundPush,
1217         FoundPop
1218     } State = Searching;
1219
1220     /* Walk over the entries. Look for a push instruction that is followed by
1221      * a pop later, where the pop is not followed by an conditional branch,
1222      * and where the value of the A register is not used later on.
1223      * Look out for the following problems:
1224      *
1225      *  - There may be another PHA/PLA inside the sequence: Restart it.
1226      *  - If the PLA has a label, all jumps to this label must be inside
1227      *    the sequence, otherwise we cannot remove the PHA/PLA.
1228      */
1229     unsigned I = 0;
1230     while (I < CS_GetEntryCount (S)) {
1231
1232         /* Get next entry */
1233         CodeEntry* E = CS_GetEntry (S, I);
1234
1235         switch (State) {
1236
1237             case Searching:
1238                 if (E->OPC == OP65_PHA) {
1239                     /* Found start of sequence */
1240                     Push  = I;
1241                     State = FoundPush;
1242                 }
1243                 break;
1244
1245             case FoundPush:
1246                 if (E->OPC == OP65_PHA) {
1247                     /* Inner push/pop, restart */
1248                     Push = I;
1249                 } else if (E->OPC == OP65_PLA) {
1250                     /* Found a matching pop */
1251                     Pop = I;
1252                     State = FoundPop;
1253                 }
1254                 break;
1255
1256             case FoundPop:
1257                 /* Next insn, just check if it is no conditional branch and
1258                  * that A is not used later. Check also that the range we have
1259                  * found now is a basic block, which means that the PHA is the
1260                  * only entrance and the PLA the only exit.
1261                  */
1262                 if ((E->Info & OF_CBRA) == 0    &&
1263                     !RegAUsed (S, I)            &&
1264                     CS_IsBasicBlock (S, Push, Pop)) {
1265                     /* We can remove the PHA and PLA instructions */
1266                     CS_DelEntry (S, Pop);
1267                     CS_DelEntry (S, Push);
1268                     /* Correct I so we continue with the next insn */
1269                     I -= 2;
1270                     /* Remember we had changes */
1271                     ++Changes;
1272                 }
1273                 /* Go into search mode again */
1274                 State = Searching;
1275                 break;
1276
1277         }
1278
1279         /* Next entry */
1280         ++I;
1281     }
1282
1283     /* Return the number of changes made */
1284     return Changes;
1285 }
1286
1287
1288
1289 unsigned OptPrecalc (CodeSeg* S)
1290 /* Replace immediate operations with the accu where the current contents are
1291  * known by a load of the final value.
1292  */
1293 {
1294     unsigned Changes = 0;
1295     unsigned I;
1296
1297     /* Generate register info for this step */
1298     CS_GenRegInfo (S);
1299
1300     /* Walk over the entries */
1301     I = 0;
1302     while (I < CS_GetEntryCount (S)) {
1303
1304         /* Get next entry */
1305         CodeEntry* E = CS_GetEntry (S, I);
1306
1307         /* Get a pointer to the output registers of the insn */
1308         const RegContents* Out = &E->RI->Out;
1309
1310         /* Argument for LDA and flag */
1311         const char* Arg = 0;
1312
1313         /* Handle the different instructions */
1314         switch (E->OPC) {
1315
1316             case OP65_LDA:
1317                 if (E->AM != AM65_IMM && RegValIsKnown (Out->RegA)) {
1318                     /* Result of load is known */
1319                     Arg = MakeHexArg (Out->RegA);
1320                 }
1321                 break;
1322
1323             case OP65_LDX:
1324                 if (E->AM != AM65_IMM && RegValIsKnown (Out->RegX)) {
1325                     /* Result of load is known */
1326                     Arg = MakeHexArg (Out->RegX);
1327                 }
1328                 break;
1329
1330             case OP65_LDY:
1331                 if (E->AM != AM65_IMM && RegValIsKnown (Out->RegY)) {
1332                     /* Result of load is known */
1333                     Arg = MakeHexArg (Out->RegY);
1334                 }
1335                 break;
1336
1337             case OP65_ADC:
1338             case OP65_ASL:
1339             case OP65_EOR:
1340             case OP65_LSR:
1341             case OP65_SBC:
1342                 if (RegValIsKnown (Out->RegA)) {
1343                     /* Accu op zp with known contents */
1344                     Arg = MakeHexArg (Out->RegA);
1345                 }
1346                 break;
1347
1348             case OP65_AND:
1349                 if (CE_KnownImm (E) && E->Num == 0xFF) {
1350                     /* AND with 0xFF, remove */
1351                     CS_DelEntry (S, I);
1352                     ++Changes;
1353                 } else if (RegValIsKnown (Out->RegA)) {
1354                     /* Accu AND zp with known contents */
1355                     Arg = MakeHexArg (Out->RegA);
1356                 }
1357                 break;
1358
1359             case OP65_ORA:
1360                 if (CE_KnownImm (E) && E->Num == 0x00) {
1361                     /* ORA with zero, remove */
1362                     CS_DelEntry (S, I);
1363                     ++Changes;
1364                 } else if (RegValIsKnown (Out->RegA)) {
1365                     /* Accu AND zp with known contents */
1366                     Arg = MakeHexArg (Out->RegA);
1367                 }
1368                 break;
1369
1370             default:
1371                 break;
1372
1373         }
1374
1375         /* Check if we have to replace the insn by LDA */
1376         if (Arg) {
1377             CodeEntry* X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, E->LI);
1378             CS_InsertEntry (S, X, I+1);
1379             CS_DelEntry (S, I);
1380             ++Changes;
1381         }
1382
1383         /* Next entry */
1384         ++I;
1385     }
1386
1387     /* Free register info */
1388     CS_FreeRegInfo (S);
1389
1390     /* Return the number of changes made */
1391     return Changes;
1392 }
1393
1394
1395
1396 /*****************************************************************************/
1397 /*                           Optimize branch types                           */
1398 /*****************************************************************************/
1399
1400
1401
1402 unsigned OptBranchDist (CodeSeg* S)
1403 /* Change branches for the distance needed. */
1404 {
1405     unsigned Changes = 0;
1406
1407     /* Walk over the entries */
1408     unsigned I = 0;
1409     while (I < CS_GetEntryCount (S)) {
1410
1411         /* Get next entry */
1412         CodeEntry* E = CS_GetEntry (S, I);
1413
1414         /* Check if it's a conditional branch to a local label. */
1415         if (E->Info & OF_CBRA) {
1416
1417             /* Is this a branch to a local symbol? */
1418             if (E->JumpTo != 0) {
1419
1420                 /* Check if the branch distance is short */
1421                 int IsShort = IsShortDist (GetBranchDist (S, I, E->JumpTo->Owner));
1422
1423                 /* Make the branch short/long according to distance */
1424                 if ((E->Info & OF_LBRA) == 0 && !IsShort) {
1425                     /* Short branch but long distance */
1426                     CE_ReplaceOPC (E, MakeLongBranch (E->OPC));
1427                     ++Changes;
1428                 } else if ((E->Info & OF_LBRA) != 0 && IsShort) {
1429                     /* Long branch but short distance */
1430                     CE_ReplaceOPC (E, MakeShortBranch (E->OPC));
1431                     ++Changes;
1432                 }
1433
1434             } else if ((E->Info & OF_LBRA) == 0) {
1435
1436                 /* Short branch to external symbol - make it long */
1437                 CE_ReplaceOPC (E, MakeLongBranch (E->OPC));
1438                 ++Changes;
1439
1440             }
1441
1442         } else if ((CPUIsets[CPU] & CPU_ISET_65SC02) != 0 &&
1443                    (E->Info & OF_UBRA) != 0               &&
1444                    E->JumpTo != 0                         &&
1445                    IsShortDist (GetBranchDist (S, I, E->JumpTo->Owner))) {
1446
1447             /* The jump is short and may be replaced by a BRA on the 65C02 CPU */
1448             CE_ReplaceOPC (E, OP65_BRA);
1449             ++Changes;
1450         }
1451
1452         /* Next entry */
1453         ++I;
1454
1455     }
1456
1457     /* Return the number of changes made */
1458     return Changes;
1459 }
1460
1461
1462