]> git.sur5r.net Git - cc65/blob - src/cc65/coptind.c
Better register tracking in the optimizer
[cc65] / src / cc65 / coptind.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 coptind.c                                 */
4 /*                                                                           */
5 /*              Environment independent low level optimizations              */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2001      Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@cc65.org                                                 */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <string.h>
37
38 /* cc65 */
39 #include "codeent.h"
40 #include "codeinfo.h"
41 #include "codeopt.h"
42 #include "error.h"
43 #include "coptind.h"
44
45
46
47 /*****************************************************************************/
48 /*                                  Macros                                   */
49 /*****************************************************************************/
50
51
52
53 /* Macro to increment and decrement register contents if they're valid */
54 #define INC(reg,val)    if ((reg) >= 0) (reg) = ((reg) + val) & 0xFF
55 #define DEC(reg,val)    if ((reg) >= 0) (reg) = ((reg) - val) & 0xFF
56
57
58
59 /*****************************************************************************/
60 /*                        Replace jumps to RTS by RTS                        */
61 /*****************************************************************************/
62
63
64
65 unsigned OptRTSJumps (CodeSeg* S)
66 /* Replace jumps to RTS by RTS */
67 {
68     unsigned Changes = 0;
69
70     /* Walk over all entries minus the last one */
71     unsigned I = 0;
72     while (I < CS_GetEntryCount (S)) {
73
74         /* Get the next entry */
75         CodeEntry* E = CS_GetEntry (S, I);
76
77         /* Check if it's an unconditional branch to a local target */
78         if ((E->Info & OF_UBRA) != 0            &&
79             E->JumpTo != 0                      &&
80             E->JumpTo->Owner->OPC == OP65_RTS) {
81
82             /* Insert an RTS instruction */
83             CodeEntry* X = NewCodeEntry (OP65_RTS, AM65_IMP, 0, 0, E->LI);
84             CS_InsertEntry (S, X, I+1);
85
86             /* Delete the jump */
87             CS_DelEntry (S, I);
88
89             /* Remember, we had changes */
90             ++Changes;
91
92         }
93
94         /* Next entry */
95         ++I;
96
97     }
98
99     /* Return the number of changes made */
100     return Changes;
101 }
102
103
104
105 /*****************************************************************************/
106 /*                             Remove dead jumps                             */
107 /*****************************************************************************/
108
109
110
111 unsigned OptDeadJumps (CodeSeg* S)
112 /* Remove dead jumps (jumps to the next instruction) */
113 {
114     unsigned Changes = 0;
115     CodeEntry* E;
116     unsigned I;
117
118     /* Get the number of entries, bail out if we have less than two entries */
119     unsigned Count = CS_GetEntryCount (S);
120     if (Count < 2) {
121         return 0;
122     }
123
124     /* Walk over all entries minus the last one */
125     I = 0;
126     while (I < Count-1) {
127
128         /* Get the next entry */
129         E = CS_GetEntry (S, I);
130
131         /* Check if it's a branch, if it has a local target, and if the target
132          * is the next instruction.
133          */
134         if (E->AM == AM65_BRA && E->JumpTo && E->JumpTo->Owner == CS_GetEntry (S, I+1)) {
135
136             /* Delete the dead jump */
137             CS_DelEntry (S, I);
138
139             /* Keep the number of entries updated */
140             --Count;
141
142             /* Remember, we had changes */
143             ++Changes;
144
145         } else {
146
147             /* Next entry */
148             ++I;
149
150         }
151     }
152
153     /* Return the number of changes made */
154     return Changes;
155 }
156
157
158
159 /*****************************************************************************/
160 /*                             Remove dead code                              */
161 /*****************************************************************************/
162
163
164
165 unsigned OptDeadCode (CodeSeg* S)
166 /* Remove dead code (code that follows an unconditional jump or an rts/rti
167  * and has no label)
168  */
169 {
170     unsigned Changes = 0;
171     unsigned I;
172
173     /* Get the number of entries, bail out if we have less than two entries */
174     unsigned Count = CS_GetEntryCount (S);
175     if (Count < 2) {
176         return 0;
177     }
178
179     /* Walk over all entries */
180     I = 0;
181     while (I < Count) {
182
183         CodeEntry* N;
184
185         /* Get this entry */
186         CodeEntry* E = CS_GetEntry (S, I);
187
188         /* Check if it's an unconditional branch, and if the next entry has
189          * no labels attached
190          */
191         if ((E->Info & OF_DEAD) != 0           &&
192             (N = CS_GetNextEntry (S, I)) != 0  &&
193             !CE_HasLabel (N)) {
194
195             /* Delete the next entry */
196             CS_DelEntry (S, I+1);
197
198             /* Keep the number of entries updated */
199             --Count;
200
201             /* Remember, we had changes */
202             ++Changes;
203
204         } else {
205
206             /* Next entry */
207             ++I;
208
209         }
210     }
211
212     /* Return the number of changes made */
213     return Changes;
214 }
215
216
217
218 /*****************************************************************************/
219 /*                          Optimize jump cascades                           */
220 /*****************************************************************************/
221
222
223
224 unsigned OptJumpCascades (CodeSeg* S)
225 /* Optimize jump cascades (jumps to jumps). In such a case, the jump is
226  * replaced by a jump to the final location. This will in some cases produce
227  * worse code, because some jump targets are no longer reachable by short
228  * branches, but this is quite rare, so there are more advantages than
229  * disadvantages.
230  */
231 {
232     unsigned Changes = 0;
233
234     /* Walk over all entries */
235     unsigned I = 0;
236     while (I < CS_GetEntryCount (S)) {
237
238         CodeEntry* N;
239         CodeLabel* OldLabel;
240
241         /* Get this entry */
242         CodeEntry* E = CS_GetEntry (S, I);
243
244         /* Check if it's a branch, if it has a jump label, if this jump
245          * label is not attached to the instruction itself, and if the
246          * target instruction is itself a branch.
247          */
248         if ((E->Info & OF_BRA) != 0        &&
249             (OldLabel = E->JumpTo) != 0    &&
250             (N = OldLabel->Owner) != E     &&
251             (N->Info & OF_BRA) != 0) {
252
253             /* Check if we can use the final target label. This is the case,
254              * if the target branch is an absolut branch, or if it is a
255              * conditional branch checking the same condition as the first one.
256              */
257             if ((N->Info & OF_UBRA) != 0 ||
258                 ((E->Info & OF_CBRA) != 0 &&
259                  GetBranchCond (E->OPC)  == GetBranchCond (N->OPC))) {
260
261                 /* This is a jump cascade and we may jump to the final target.
262                  * Insert a new instruction, then remove the old one
263                  */
264                 CodeEntry* X = NewCodeEntry (E->OPC, E->AM, N->Arg, N->JumpTo, E->LI);
265
266                 /* Insert it behind E */
267                 CS_InsertEntry (S, X, I+1);
268
269                 /* Remove E */
270                 CS_DelEntry (S, I);
271
272                 /* Remember, we had changes */
273                 ++Changes;
274
275                 /* Done */
276                 continue;
277
278             }
279
280             /* Check if both are conditional branches, and the condition of
281              * the second is the inverse of that of the first. In this case,
282              * the second branch will never be taken, and we may jump directly
283              * to the instruction behind this one.
284              */
285             if ((E->Info & OF_CBRA) != 0 && (N->Info & OF_CBRA) != 0) {
286
287                 CodeEntry* X;   /* Instruction behind N */
288                 CodeLabel* LX;  /* Label attached to X */
289
290                 /* Get the branch conditions of both branches */
291                 bc_t BC1 = GetBranchCond (E->OPC);
292                 bc_t BC2 = GetBranchCond (N->OPC);
293
294                 /* Check the branch conditions */
295                 if (BC1 != GetInverseCond (BC2)) {
296                     /* Condition not met */
297                     goto NextEntry;
298                 }
299
300                 /* We may jump behind this conditional branch. Get the
301                  * pointer to the next instruction
302                  */
303                 if ((X = CS_GetNextEntry (S, CS_GetEntryIndex (S, N))) == 0) {
304                     /* N is the last entry, bail out */
305                     goto NextEntry;
306                 }
307
308                 /* Get the label attached to X, create a new one if needed */
309                 LX = CS_GenLabel (S, X);
310
311                 /* Move the reference from E to the new label */
312                 CS_MoveLabelRef (S, E, LX);
313
314                 /* Remember, we had changes */
315                 ++Changes;
316
317                 /* Done */
318                 continue;
319
320             }
321         }
322
323 NextEntry:
324         /* Next entry */
325         ++I;
326
327     }
328
329     /* Return the number of changes made */
330     return Changes;
331 }
332
333
334
335 /*****************************************************************************/
336 /*                             Optimize jsr/rts                              */
337 /*****************************************************************************/
338
339
340
341 unsigned OptRTS (CodeSeg* S)
342 /* Optimize subroutine calls followed by an RTS. The subroutine call will get
343  * replaced by a jump. Don't bother to delete the RTS if it does not have a
344  * label, the dead code elimination should take care of it.
345  */
346 {
347     unsigned Changes = 0;
348     unsigned I;
349
350     /* Get the number of entries, bail out if we have less than 2 entries */
351     unsigned Count = CS_GetEntryCount (S);
352     if (Count < 2) {
353         return 0;
354     }
355
356     /* Walk over all entries minus the last one */
357     I = 0;
358     while (I < Count-1) {
359
360         CodeEntry* N;
361
362         /* Get this entry */
363         CodeEntry* E = CS_GetEntry (S, I);
364
365         /* Check if it's a subroutine call and if the following insn is RTS */
366         if (E->OPC == OP65_JSR                    &&
367             (N = CS_GetNextEntry (S, I)) != 0 &&
368             N->OPC == OP65_RTS) {
369
370             /* Change the jsr to a jmp and use the additional info for a jump */
371             E->AM = AM65_BRA;
372             CE_ReplaceOPC (E, OP65_JMP);
373
374             /* Remember, we had changes */
375             ++Changes;
376
377         }
378
379         /* Next entry */
380         ++I;
381
382     }
383
384     /* Return the number of changes made */
385     return Changes;
386 }
387
388
389
390 /*****************************************************************************/
391 /*                           Optimize jump targets                           */
392 /*****************************************************************************/
393
394
395
396 unsigned OptJumpTarget (CodeSeg* S)
397 /* If the instruction preceeding an unconditional branch is the same as the
398  * instruction preceeding the jump target, the jump target may be moved
399  * one entry back. This is a size optimization, since the instruction before
400  * the branch gets removed.
401  */
402 {
403     unsigned Changes = 0;
404     CodeEntry* E1;              /* Entry 1 */
405     CodeEntry* E2;              /* Entry 2 */
406     CodeEntry* T1;              /* Jump target entry 1 */
407     CodeEntry* T2;              /* Jump target entry 2 */
408     CodeLabel* TL1;             /* Target label 1 */
409     unsigned TI;                /* Target index */
410     unsigned I;
411
412     /* Get the number of entries, bail out if we have not enough */
413     unsigned Count = CS_GetEntryCount (S);
414     if (Count < 3) {
415         return 0;
416     }
417
418     /* Walk over the entries */
419     I = 0;
420     while (I < Count-1) {
421
422         /* Get next entry */
423         E2 = CS_GetEntry (S, I+1);
424
425         /* Check if we have a jump or branch, and a matching label */
426         if ((E2->Info & OF_UBRA) != 0 && E2->JumpTo) {
427
428             /* Get the target instruction for the label */
429             T2 = E2->JumpTo->Owner;
430
431             /* Get the entry preceeding this one (if possible) */
432             TI = CS_GetEntryIndex (S, T2);
433             if (TI == 0) {
434                 /* There is no entry before this one */
435                 goto NextEntry;
436             }
437             T1 = CS_GetEntry (S, TI-1);
438
439             /* Get the entry preceeding the jump */
440             E1 = CS_GetEntry (S, I);
441
442             /* Check if both preceeding instructions are identical */
443             if (!CodeEntriesAreEqual (E1, T1)) {
444                 /* Not equal, try next */
445                 goto NextEntry;
446             }
447
448             /* Get the label for the instruction preceeding the jump target.
449              * This routine will create a new label if the instruction does
450              * not already have one.
451              */
452             TL1 = CS_GenLabel (S, T1);
453
454             /* Change the jump target to point to this new label */
455             CS_MoveLabelRef (S, E2, TL1);
456
457             /* If the instruction preceeding the jump has labels attached,
458              * move references to this label to the new label.
459              */
460             if (CE_HasLabel (E1)) {
461                 CS_MoveLabels (S, E1, T1);
462             }
463
464             /* Remove the entry preceeding the jump */
465             CS_DelEntry (S, I);
466             --Count;
467
468             /* Remember, we had changes */
469             ++Changes;
470
471         }
472
473 NextEntry:
474         /* Next entry */
475         ++I;
476
477     }
478
479     /* Return the number of changes made */
480     return Changes;
481 }
482
483
484
485 /*****************************************************************************/
486 /*                       Optimize conditional branches                       */
487 /*****************************************************************************/
488
489
490
491 unsigned OptCondBranches (CodeSeg* S)
492 /* Performs several optimization steps:
493  *
494  *  - If an immidiate load of a register is followed by a conditional jump that
495  *    is never taken because the load of the register sets the flags in such a
496  *    manner, remove the conditional branch.
497  *  - If the conditional branch is always taken because of the register load,
498  *    replace it by a jmp.
499  *  - If a conditional branch jumps around an unconditional branch, remove the
500  *    conditional branch and make the jump a conditional branch with the
501  *    inverse condition of the first one.
502  */
503 {
504     unsigned Changes = 0;
505     unsigned I;
506
507     /* Get the number of entries, bail out if we have not enough */
508     unsigned Count = CS_GetEntryCount (S);
509     if (Count < 2) {
510         return 0;
511     }
512
513     /* Walk over the entries */
514     I = 0;
515     while (I < Count-1) {
516
517         CodeEntry* N;
518         CodeLabel* L;
519
520         /* Get next entry */
521         CodeEntry* E = CS_GetEntry (S, I);
522
523         /* Check if it's a register load */
524         if ((E->Info & OF_LOAD) != 0              &&  /* It's a load instruction */
525             E->AM == AM65_IMM                     &&  /* ..with immidiate addressing */
526             (E->Flags & CEF_NUMARG) != 0          &&  /* ..and a numeric argument. */
527             (N = CS_GetNextEntry (S, I)) != 0     &&  /* There is a following entry */
528             (N->Info & OF_CBRA) != 0              &&  /* ..which is a conditional branch */
529             !CE_HasLabel (N)) {               /* ..and does not have a label */
530
531             /* Get the branch condition */
532             bc_t BC = GetBranchCond (N->OPC);
533
534             /* Check the argument against the branch condition */
535             if ((BC == BC_EQ && E->Num != 0)            ||
536                 (BC == BC_NE && E->Num == 0)            ||
537                 (BC == BC_PL && (E->Num & 0x80) != 0)   ||
538                 (BC == BC_MI && (E->Num & 0x80) == 0)) {
539
540                 /* Remove the conditional branch */
541                 CS_DelEntry (S, I+1);
542                 --Count;
543
544                 /* Remember, we had changes */
545                 ++Changes;
546
547             } else if ((BC == BC_EQ && E->Num == 0)             ||
548                        (BC == BC_NE && E->Num != 0)             ||
549                        (BC == BC_PL && (E->Num & 0x80) == 0)    ||
550                        (BC == BC_MI && (E->Num & 0x80) != 0)) {
551
552                 /* The branch is always taken, replace it by a jump */
553                 CE_ReplaceOPC (N, OP65_JMP);
554
555                 /* Remember, we had changes */
556                 ++Changes;
557             }
558
559         }
560
561         if ((E->Info & OF_CBRA) != 0              &&  /* It's a conditional branch */
562             (L = E->JumpTo) != 0                  &&  /* ..referencing a local label */
563             (N = CS_GetNextEntry (S, I)) != 0     &&  /* There is a following entry */
564             (N->Info & OF_UBRA) != 0              &&  /* ..which is an uncond branch, */
565             !CE_HasLabel (N)                      &&  /* ..has no label attached */
566             L->Owner == CS_GetNextEntry (S, I+1)) {/* ..and jump target follows */
567
568             /* Replace the jump by a conditional branch with the inverse branch
569              * condition than the branch around it.
570              */
571             CE_ReplaceOPC (N, GetInverseBranch (E->OPC));
572
573             /* Remove the conditional branch */
574             CS_DelEntry (S, I);
575             --Count;
576
577             /* Remember, we had changes */
578             ++Changes;
579
580         }
581
582         /* Next entry */
583         ++I;
584
585     }
586
587     /* Return the number of changes made */
588     return Changes;
589 }
590
591
592
593 /*****************************************************************************/
594 /*                            Remove unused loads                            */
595 /*****************************************************************************/
596
597
598
599 unsigned OptUnusedLoads (CodeSeg* S)
600 /* Remove loads of registers where the value loaded is not used later. */
601 {
602     unsigned Changes = 0;
603
604     /* Walk over the entries */
605     unsigned I = 0;
606     while (I < CS_GetEntryCount (S)) {
607
608         CodeEntry* N;
609
610         /* Get next entry */
611         CodeEntry* E = CS_GetEntry (S, I);
612
613         /* Check if it's a register load or transfer insn */
614         if ((E->Info & (OF_LOAD | OF_XFR)) != 0    &&
615             (N = CS_GetNextEntry (S, I)) != 0      &&
616             (N->Info & OF_FBRA) == 0) {
617
618             /* Check which sort of load or transfer it is */
619             unsigned R;
620             switch (E->OPC) {
621                 case OP65_TXA:
622                 case OP65_TYA:
623                 case OP65_LDA:  R = REG_A;      break;
624                 case OP65_TAX:
625                 case OP65_LDX:  R = REG_X;      break;
626                 case OP65_TAY:
627                 case OP65_LDY:  R = REG_Y;      break;
628                 default:        goto NextEntry;         /* OOPS */
629             }
630
631             /* Get register usage and check if the register value is used later */
632             if ((GetRegInfo (S, I+1) & R) == 0) {
633
634                 /* Register value is not used, remove the load */
635                 CS_DelEntry (S, I);
636
637                 /* Remember, we had changes */
638                 ++Changes;
639
640             }
641         }
642
643 NextEntry:
644         /* Next entry */
645         ++I;
646
647     }
648
649     /* Return the number of changes made */
650     return Changes;
651 }
652
653
654
655 unsigned OptDuplicateLoads (CodeSeg* S)
656 /* Remove loads of registers where the value loaded is already in the register. */
657 {
658     unsigned Changes = 0;
659     unsigned I;
660
661     /* Generate register info for this step */
662     CS_GenRegInfo (S);
663
664     /* Walk over the entries */
665     I = 0;
666     while (I < CS_GetEntryCount (S)) {
667
668         CodeEntry* N;
669
670         /* Get next entry */
671         CodeEntry* E = CS_GetEntry (S, I);
672
673         /* Assume we won't delete the entry */
674         int Delete = 0;
675
676         /* Handle the different instructions */
677         switch (E->OPC) {
678
679             case OP65_LDA:
680                 if (E->RI->In.RegA >= 0               && /* Value of A is known */
681                     CE_KnownImm (E)                   && /* Value to be loaded is known */
682                     E->RI->In.RegA == E->Num          && /* Both are equal */
683                     (N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */
684                     (N->Info & OF_FBRA) == 0) {          /* Which is not a cond branch */
685                     Delete = 1;
686                 }
687                 break;
688
689             case OP65_LDX:
690                 if (E->RI->In.RegX >= 0               && /* Value of X is known */
691                     CE_KnownImm (E)                   && /* Value to be loaded is known */
692                     E->RI->In.RegX == E->Num          && /* Both are equal */
693                     (N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */
694                     (N->Info & OF_FBRA) == 0) {          /* Which is not a cond branch */
695                     Delete = 1;
696                 }
697                 break;
698
699             case OP65_LDY:
700                 if (E->RI->In.RegY >= 0               && /* Value of Y is known */
701                     CE_KnownImm (E)                   && /* Value to be loaded is known */
702                     E->RI->In.RegY == E->Num          && /* Both are equal */
703                     (N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */
704                     (N->Info & OF_FBRA) == 0) {          /* Which is not a cond branch */
705                     Delete = 1;
706                 }
707                 break;
708
709             case OP65_STX:
710                 /* If the value in the X register is known and the same as
711                  * that in the A register, replace the store by a STA. The
712                  * optimizer will then remove the load instruction for X
713                  * later. STX does support the zeropage,y addressing mode,
714                  * so be sure to check for that.
715                  */
716                 if (E->RI->In.RegX >= 0               &&
717                     E->RI->In.RegX == E->RI->In.RegA  &&
718                     E->AM != AM65_ABSY                &&
719                     E->AM != AM65_ZPY) {
720                     /* Use the A register instead */
721                     CE_ReplaceOPC (E, OP65_STA);
722                 }                               
723                 break;
724
725             case OP65_STY:
726                 /* If the value in the Y register is known and the same as
727                  * that in the A register, replace the store by a STA. The
728                  * optimizer will then remove the load instruction for Y
729                  * later. If replacement by A is not possible try a
730                  * replacement by X, but check for invalid addressing modes
731                  * in this case.
732                  */
733                 if (E->RI->In.RegY >= 0) {
734                     if (E->RI->In.RegY == E->RI->In.RegA) {
735                         CE_ReplaceOPC (E, OP65_STA);
736                     } else if (E->RI->In.RegY == E->RI->In.RegX &&
737                                E->AM != AM65_ABSX               &&
738                                E->AM != AM65_ZPX) {
739                         CE_ReplaceOPC (E, OP65_STX);
740                     }
741                 }
742                 break;
743
744             case OP65_TAX:
745                 if (E->RI->In.RegA >= 0                 &&
746                     E->RI->In.RegA == E->RI->In.RegX    &&
747                     (N = CS_GetNextEntry (S, I)) != 0   &&
748                     (N->Info & OF_FBRA) == 0) {
749                     /* Value is identical and not followed by a branch */
750                     Delete = 1;
751                 }
752                 break;
753
754             case OP65_TAY:
755                 if (E->RI->In.RegA >= 0                 &&
756                     E->RI->In.RegA == E->RI->In.RegY    &&
757                     (N = CS_GetNextEntry (S, I)) != 0   &&
758                     (N->Info & OF_FBRA) == 0) {
759                     /* Value is identical and not followed by a branch */
760                     Delete = 1;
761                 }
762                 break;
763
764             case OP65_TXA:
765                 if (E->RI->In.RegX >= 0                 &&
766                     E->RI->In.RegX == E->RI->In.RegA    &&
767                     (N = CS_GetNextEntry (S, I)) != 0   &&
768                     (N->Info & OF_FBRA) == 0) {
769                     /* Value is identical and not followed by a branch */
770                     Delete = 1;
771                 }
772                 break;
773
774             case OP65_TYA:
775                 if (E->RI->In.RegY >= 0                 &&
776                     E->RI->In.RegY == E->RI->In.RegA    &&
777                     (N = CS_GetNextEntry (S, I)) != 0   &&
778                     (N->Info & OF_FBRA) == 0) {
779                     /* Value is identical and not followed by a branch */
780                     Delete = 1;
781                 }
782                 break;
783
784             default:
785                 break;
786
787         }
788
789         /* Delete the entry if requested */
790         if (Delete) {
791
792             /* Register value is not used, remove the load */
793             CS_DelEntry (S, I);
794
795             /* Remember, we had changes */
796             ++Changes;
797
798         } else {
799
800             /* Next entry */
801             ++I;
802
803         }
804
805     }
806
807     /* Return the number of changes made */
808     return Changes;
809 }
810
811
812
813 unsigned OptStoreLoad (CodeSeg* S)
814 /* Remove a store followed by a load from the same location. */
815 {
816     unsigned Changes = 0;
817
818     /* Walk over the entries */
819     unsigned I = 0;
820     while (I < CS_GetEntryCount (S)) {
821
822         CodeEntry* N;
823         CodeEntry* X;
824
825         /* Get next entry */
826         CodeEntry* E = CS_GetEntry (S, I);
827
828         /* Check if it is a store instruction followed by a load from the
829          * same address which is itself not followed by a conditional branch.
830          */
831         if ((E->Info & OF_STORE) != 0                 &&
832             (N = CS_GetNextEntry (S, I)) != 0         &&
833             (N->Info & OF_LOAD) != 0                  &&
834             strcmp (E->Arg, N->Arg) == 0              &&
835             (X = CS_GetNextEntry (S, I+1)) != 0       &&
836             (X->Info & OF_FBRA) == 0) {
837
838             /* Register value is not used, remove the load */
839             CS_DelEntry (S, I+1);
840
841             /* Remember, we had changes */
842             ++Changes;
843
844         }
845
846         /* Next entry */
847         ++I;
848
849     }
850
851     /* Return the number of changes made */
852     return Changes;
853 }
854
855
856
857 /*****************************************************************************/
858 /*                           Optimize branch types                           */
859 /*****************************************************************************/
860
861
862
863 unsigned OptBranchDist (CodeSeg* S)
864 /* Change branches for the distance needed. */
865 {
866     unsigned Changes = 0;
867     unsigned I;
868
869     /* Get the number of entries, bail out if we have not enough */
870     unsigned Count = CS_GetEntryCount (S);
871
872     /* Walk over the entries */
873     I = 0;
874     while (I < Count) {
875
876         /* Get next entry */
877         CodeEntry* E = CS_GetEntry (S, I);
878
879         /* Check if it's a conditional branch to a local label. */
880         if ((E->Info & OF_CBRA) != 0) {
881
882             /* Is this a branch to a local symbol? */
883             if (E->JumpTo != 0) {
884
885                 /* Get the index of the branch target */
886                 unsigned TI = CS_GetEntryIndex (S, E->JumpTo->Owner);
887
888                 /* Determine the branch distance */
889                 int Distance = 0;
890                 if (TI >= I) {
891                     /* Forward branch */
892                     unsigned J = I;
893                     while (J < TI) {
894                         CodeEntry* N = CS_GetEntry (S, J++);
895                         Distance += N->Size;
896                     }
897                 } else {
898                     /* Backward branch */
899                     unsigned J = TI;
900                     while (J < I) {
901                         CodeEntry* N = CS_GetEntry (S, J++);
902                         Distance += N->Size;
903                     }
904                 }
905
906                 /* Make the branch short/long according to distance */
907                 if ((E->Info & OF_LBRA) == 0 && Distance > 120) {
908                     /* Short branch but long distance */
909                     CE_ReplaceOPC (E, MakeLongBranch (E->OPC));
910                     ++Changes;
911                 } else if ((E->Info & OF_LBRA) != 0 && Distance < 120) {
912                     /* Long branch but short distance */
913                     CE_ReplaceOPC (E, MakeShortBranch (E->OPC));
914                     ++Changes;
915                 }
916
917             } else if ((E->Info & OF_LBRA) == 0) {
918
919                 /* Short branch to external symbol - make it long */
920                 CE_ReplaceOPC (E, MakeLongBranch (E->OPC));
921                 ++Changes;
922
923             }
924         }
925
926         /* Next entry */
927         ++I;
928
929     }
930
931     /* Return the number of changes made */
932     return Changes;
933 }
934
935
936