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