]> git.sur5r.net Git - cc65/blob - src/cc65/coptcmp.c
Fixed some bugs
[cc65] / src / cc65 / coptcmp.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 coptcmp.c                                 */
4 /*                                                                           */
5 /*                             Optimize compares                             */
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 "error.h"
42 #include "coptcmp.h"
43
44
45
46 /*****************************************************************************/
47 /*                                   Data                                    */
48 /*****************************************************************************/
49
50
51
52 /* Defines for the conditions in a compare */
53 typedef enum {
54     CMP_INV = -1,
55     CMP_EQ,
56     CMP_NE,
57     CMP_GT,
58     CMP_GE,
59     CMP_LT,
60     CMP_LE,
61     CMP_UGT,
62     CMP_UGE,
63     CMP_ULT,
64     CMP_ULE
65 } cmp_t;
66
67 /* Table with the compare suffixes */
68 static const char CmpSuffixTab [][4] = {
69     "eq", "ne", "gt", "ge", "lt", "le", "ugt", "uge", "ult", "ule"
70 };
71
72 /* Table used to invert a condition, indexed by condition */
73 static const unsigned char CmpInvertTab [] = {
74     CMP_NE, CMP_EQ,
75     CMP_LE, CMP_LT, CMP_GE, CMP_GT,
76     CMP_ULE, CMP_ULT, CMP_UGE, CMP_UGT
77 };
78
79 /* Table to show which compares are signed (use the N flag) */
80 static const char CmpSignedTab [] = {
81     0, 0, 1, 1, 1, 1, 0, 0, 0, 0
82 };
83
84
85
86 /*****************************************************************************/
87 /*                             Helper functions                              */
88 /*****************************************************************************/
89
90
91
92 static cmp_t FindCmpCond (const char* Code, unsigned CodeLen)
93 /* Search for a compare condition by the given code using the given length */
94 {
95     unsigned I;
96
97     /* Linear search */
98     for (I = 0; I < sizeof (CmpSuffixTab) / sizeof (CmpSuffixTab [0]); ++I) {
99         if (strncmp (Code, CmpSuffixTab [I], CodeLen) == 0) {
100             /* Found */
101             return I;
102         }
103     }
104
105     /* Not found */
106     return CMP_INV;
107 }
108
109
110
111 static cmp_t FindBoolCmpCond (const char* Name)
112 /* Map a condition suffix to a code. Return the code or CMP_INV on failure */
113 {
114     /* Check for the correct subroutine name */
115     if (strncmp (Name, "bool", 4) == 0) {
116         /* Name is ok, search for the code in the table */
117         return FindCmpCond (Name+4, strlen(Name)-4);
118     } else {
119         /* Not found */
120         return CMP_INV;
121     }
122 }
123
124
125
126 static cmp_t FindTosCmpCond (const char* Name)
127 /* Check if this is a call to one of the TOS compare functions (tosgtax).
128  * Return the condition code or CMP_INV on failure.
129  */
130 {
131     unsigned Len = strlen (Name);
132
133     /* Check for the correct subroutine name */
134     if (strncmp (Name, "tos", 3) == 0 && strcmp (Name+Len-2, "ax") == 0) {
135         /* Name is ok, search for the code in the table */
136         return FindCmpCond (Name+3, Len-3-2);
137     } else {
138         /* Not found */
139         return CMP_INV;
140     }
141 }
142
143
144
145 static void ReplaceCmp (CodeSeg* S, unsigned I, cmp_t Cond)
146 /* Helper function for the replacement of routines that return a boolean
147  * followed by a conditional jump. Instead of the boolean value, the condition
148  * codes are evaluated directly.
149  * I is the index of the conditional branch, the sequence is already checked
150  * to be correct.
151  */
152 {
153     CodeEntry* N;
154     CodeLabel* L;
155
156     /* Get the entry */
157     CodeEntry* E = CS_GetEntry (S, I);
158
159     /* Replace the conditional branch */
160     switch (Cond) {
161
162         case CMP_EQ:
163             CE_ReplaceOPC (E, OP65_JEQ);
164             break;
165
166         case CMP_NE:
167             CE_ReplaceOPC (E, OP65_JNE);
168             break;
169
170         case CMP_GT:
171             /* Replace by
172              *     beq @L
173              *     jpl Target
174              * @L: ...
175              */
176             if ((N = CS_GetNextEntry (S, I)) == 0) {
177                 /* No such entry */
178                 Internal ("Invalid program flow");
179             }
180             L = CS_GenLabel (S, N);
181             N = NewCodeEntry (OP65_BEQ, AM65_BRA, L->Name, L, E->LI);
182             CS_InsertEntry (S, N, I);
183             CE_ReplaceOPC (E, OP65_JPL);
184             break;
185
186         case CMP_GE:
187             CE_ReplaceOPC (E, OP65_JPL);
188             break;
189
190         case CMP_LT:
191             CE_ReplaceOPC (E, OP65_JMI);
192             break;
193
194         case CMP_LE:
195             /* Replace by
196              *     jmi Target
197              *     jeq Target
198              */
199             CE_ReplaceOPC (E, OP65_JMI);
200             L = E->JumpTo;
201             N = NewCodeEntry (OP65_JEQ, AM65_BRA, L->Name, L, E->LI);
202             CS_InsertEntry (S, N, I+1);
203             break;
204
205         case CMP_UGT:
206             /* Replace by
207              *     beq @L
208              *     jcs Target
209              * @L: ...
210              */
211             if ((N = CS_GetNextEntry (S, I)) == 0) {
212                 /* No such entry */
213                 Internal ("Invalid program flow");
214             }
215             L = CS_GenLabel (S, N);
216             N = NewCodeEntry (OP65_BEQ, AM65_BRA, L->Name, L, E->LI);
217             CS_InsertEntry (S, N, I);
218             CE_ReplaceOPC (E, OP65_JCS);
219             break;
220
221         case CMP_UGE:
222             CE_ReplaceOPC (E, OP65_JCS);
223             break;
224
225         case CMP_ULT:
226             CE_ReplaceOPC (E, OP65_JCC);
227             break;
228
229         case CMP_ULE:
230             /* Replace by
231              *     jcc Target
232              *     jeq Target
233              */
234             CE_ReplaceOPC (E, OP65_JCC);
235             L = E->JumpTo;
236             N = NewCodeEntry (OP65_JEQ, AM65_BRA, L->Name, L, E->LI);
237             CS_InsertEntry (S, N, I+1);
238             break;
239
240         default:
241             Internal ("Unknown jump condition: %d", Cond);
242
243     }
244
245 }
246
247
248
249 static int IsImmCmp16 (CodeEntry** L)
250 /* Check if the instructions at L are an immidiate compare of a/x:
251  *
252  *
253  */
254 {
255     return (L[0]->OPC == OP65_CPX                              &&
256             L[0]->AM == AM65_IMM                               &&
257             (L[0]->Flags & CEF_NUMARG) != 0                    &&
258             !CE_HasLabel (L[0])                                &&
259             (L[1]->OPC == OP65_JNE || L[1]->OPC == OP65_BNE)   &&
260             L[1]->JumpTo != 0                                  &&
261             !CE_HasLabel (L[1])                                &&
262             L[2]->OPC == OP65_CMP                              &&
263             L[2]->AM == AM65_IMM                               &&
264             (L[2]->Flags & CEF_NUMARG) != 0                    &&
265             (L[3]->Info & OF_CBRA) != 0                        &&
266             L[3]->JumpTo != 0                                  &&
267             (L[1]->JumpTo->Owner == L[3] || L[1]->JumpTo == L[3]->JumpTo));
268 }
269
270
271
272 static int GetCmpRegVal (const CodeEntry* E)
273 /* Return the register value for an immediate compare */
274 {
275     switch (E->OPC) {
276         case OP65_CMP: return E->RI->In.RegA;
277         case OP65_CPX: return E->RI->In.RegX;
278         case OP65_CPY: return E->RI->In.RegY;
279         default:       Internal ("Invalid opcode in GetCmpRegVal");
280                        return 0;  /* Not reached */
281     }
282 }
283
284
285
286 static int IsCmpToZero (const CodeEntry* E)
287 /* Check if the given instrcuction is a compare to zero instruction */
288 {
289     return (E->OPC == OP65_CMP            &&
290             E->AM  == AM65_IMM            &&
291             (E->Flags & CEF_NUMARG) != 0  &&
292             E->Num == 0);
293 }
294
295
296
297 static int IsSpLoad (const CodeEntry* E)
298 /* Return true if this is the load of A from the stack */
299 {
300     return E->OPC == OP65_LDA && E->AM == AM65_ZP_INDY && strcmp (E->Arg, "sp") == 0;
301 }
302
303
304
305 static int IsLocalLoad16 (CodeSeg* S, unsigned Index,
306                           CodeEntry** L, unsigned Count)
307 /* Check if a 16 bit load of a local variable follows:
308  *
309  *      ldy     #$xx
310  *      lda     (sp),y
311  *      tax
312  *      dey
313  *      lda     (sp),y
314  *
315  * If so, read Count entries following the first ldy into L and return true
316  * if this is possible. Otherwise return false.
317  */
318 {
319     /* Be sure we read enough entries for the check */
320     CHECK (Count >= 5);
321
322     /* Read the first entry */
323     L[0] = CS_GetEntry (S, Index);
324
325     /* Check for the sequence */
326     return (L[0]->OPC == OP65_LDY                        &&
327             CE_KnownImm (L[0])                           &&
328             CS_GetEntries (S, L+1, Index+1, Count-1)     &&
329             IsSpLoad (L[1])                              &&
330             !CE_HasLabel (L[1])                          &&
331             L[2]->OPC == OP65_TAX                        &&
332             !CE_HasLabel (L[2])                          &&
333             L[3]->OPC == OP65_LDY                        &&
334             CE_KnownImm (L[3])                           &&
335             L[3]->Num == L[0]->Num - 1                   &&
336             !CE_HasLabel (L[3])                          &&
337             IsSpLoad (L[4])                              &&
338             !CE_HasLabel (L[4]));
339 }
340
341
342
343 /*****************************************************************************/
344 /*             Remove calls to the bool transformer subroutines              */
345 /*****************************************************************************/
346
347
348
349 unsigned OptBoolTrans (CodeSeg* S)
350 /* Try to remove the call to boolean transformer routines where the call is
351  * not really needed.
352  */
353 {
354     unsigned Changes = 0;
355
356     /* Walk over the entries */
357     unsigned I = 0;
358     while (I < CS_GetEntryCount (S)) {
359
360         CodeEntry* N;
361         cmp_t Cond;
362
363         /* Get next entry */
364         CodeEntry* E = CS_GetEntry (S, I);
365
366         /* Check for a boolean transformer */
367         if (E->OPC == OP65_JSR                           &&
368             (Cond = FindBoolCmpCond (E->Arg)) != CMP_INV &&
369             (N = CS_GetNextEntry (S, I)) != 0        &&
370             (N->Info & OF_ZBRA) != 0) {
371
372             /* Make the boolean transformer unnecessary by changing the
373              * the conditional jump to evaluate the condition flags that
374              * are set after the compare directly. Note: jeq jumps if
375              * the condition is not met, jne jumps if the condition is met.
376              * Invert the code if we jump on condition not met.
377              */
378             if (GetBranchCond (N->OPC) == BC_EQ) {
379                 /* Jumps if condition false, invert condition */
380                 Cond = CmpInvertTab [Cond];
381             }
382
383             /* Check if we can replace the code by something better */
384             ReplaceCmp (S, I+1, Cond);
385
386             /* Remove the call to the bool transformer */
387             CS_DelEntry (S, I);
388
389             /* Remember, we had changes */
390             ++Changes;
391
392         }
393
394         /* Next entry */
395         ++I;
396
397     }
398
399     /* Return the number of changes made */
400     return Changes;
401 }
402
403
404
405 /*****************************************************************************/
406 /*                        Optimizations for compares                         */
407 /*****************************************************************************/
408
409
410
411 unsigned OptCmp1 (CodeSeg* S)
412 /* Search for the sequence
413  *
414  *      stx     xx
415  *      stx     tmp1
416  *      ora     tmp1
417  *
418  * and replace it by
419  *
420  *      stx     xx
421  *      ora     xx
422  */
423 {
424     unsigned Changes = 0;
425
426     /* Walk over the entries */
427     unsigned I = 0;
428     while (I < CS_GetEntryCount (S)) {
429
430         CodeEntry* L[2];
431
432         /* Get next entry */
433         CodeEntry* E = CS_GetEntry (S, I);
434
435         /* Check for the sequence */
436         if (E->OPC == OP65_STX                  &&
437             CS_GetEntries (S, L, I+1, 2)        &&
438             L[0]->OPC == OP65_STX               &&
439             strcmp (L[0]->Arg, "tmp1") == 0     &&
440             !CE_HasLabel (L[0])                 &&
441             L[1]->OPC == OP65_ORA               &&
442             strcmp (L[1]->Arg, "tmp1") == 0     &&
443             !CE_HasLabel (L[1])) {
444
445             /* Remove the remaining instructions */
446             CS_DelEntries (S, I+1, 2);
447
448             /* Insert the ora instead */
449             CS_InsertEntry (S, NewCodeEntry (OP65_ORA, E->AM, E->Arg, 0, E->LI), I+1);
450
451             /* Remember, we had changes */
452             ++Changes;
453
454         }
455
456         /* Next entry */
457         ++I;
458
459     }
460
461     /* Return the number of changes made */
462     return Changes;
463 }
464
465
466
467 unsigned OptCmp2 (CodeSeg* S)
468 /* Search for
469  *
470  *      lda/and/ora/eor ...
471  *      cmp #$00
472  *      jeq/jne
473  * or
474  *      lda/and/ora/eor ...
475  *      cmp #$00
476  *      jsr boolxx
477  *
478  * and remove the cmp.
479  */
480 {
481     unsigned Changes = 0;
482
483     /* Walk over the entries */
484     unsigned I = 0;
485     while (I < CS_GetEntryCount (S)) {
486
487         CodeEntry* L[2];
488
489         /* Get next entry */
490         CodeEntry* E = CS_GetEntry (S, I);
491
492         /* Check for the sequence */
493         if ((E->OPC == OP65_ADC ||
494              E->OPC == OP65_AND ||
495              E->OPC == OP65_DEA ||
496              E->OPC == OP65_EOR ||
497              E->OPC == OP65_INA ||
498              E->OPC == OP65_LDA ||
499              E->OPC == OP65_ORA ||
500              E->OPC == OP65_PLA ||
501              E->OPC == OP65_SBC ||
502              E->OPC == OP65_TXA ||
503              E->OPC == OP65_TYA)                       &&
504             CS_GetEntries (S, L, I+1, 2)               &&
505             IsCmpToZero (L[0])                         &&
506             !CE_HasLabel (L[0])                        &&
507             ((L[1]->Info & OF_FBRA) != 0         ||
508              (L[1]->OPC == OP65_JSR        &&
509               FindBoolCmpCond (L[1]->Arg) != CMP_INV)) &&
510             !CE_HasLabel (L[1])) {
511
512             /* Remove the compare */
513             CS_DelEntry (S, I+1);
514
515             /* Remember, we had changes */
516             ++Changes;
517
518         }
519
520         /* Next entry */
521         ++I;
522
523     }
524
525     /* Return the number of changes made */
526     return Changes;
527 }
528
529
530
531 unsigned OptCmp3 (CodeSeg* S)
532 /* Search for
533  *
534  *      lda     x
535  *      ldx     y
536  *      cpx     #a
537  *      bne     L1
538  *      cmp     #b
539  * L1:  jne/jeq L2
540  *
541  * If a is zero, we may remove the compare. If a and b are both zero, we may
542  * replace it by the sequence
543  *
544  *      lda     x
545  *      ora     x+1
546  *      jne/jeq ...
547  *
548  * L1 may be either the label at the branch instruction, or the target label
549  * of this instruction.
550  */
551 {
552     unsigned Changes = 0;
553
554     /* Walk over the entries */
555     unsigned I = 0;
556     while (I < CS_GetEntryCount (S)) {
557
558         CodeEntry* L[5];
559
560         /* Get next entry */
561         CodeEntry* E = CS_GetEntry (S, I);
562
563         /* Check for the sequence */
564         if (E->OPC == OP65_LDA               &&
565             CS_GetEntries (S, L, I+1, 5) &&
566             L[0]->OPC == OP65_LDX            &&
567             !CE_HasLabel (L[0])              &&
568             IsImmCmp16 (L+1)                 &&
569             !RegAXUsed (S, I+6)) {
570
571             if ((L[4]->Info & OF_FBRA) != 0 && L[1]->Num == 0 && L[3]->Num == 0) {
572                 /* The value is zero, we may use the simple code version. */
573                 CE_ReplaceOPC (L[0], OP65_ORA);
574                 CS_DelEntries (S, I+2, 3);
575             } else {
576                 /* Move the lda instruction after the first branch. This will
577                  * improve speed, since the load is delayed after the first
578                  * test.
579                  */
580                 CS_MoveEntry (S, I, I+4);
581
582                 /* We will replace the ldx/cpx by lda/cmp */
583                 CE_ReplaceOPC (L[0], OP65_LDA);
584                 CE_ReplaceOPC (L[1], OP65_CMP);
585
586                 /* Beware: If the first LDA instruction had a label, we have
587                  * to move this label to the top of the sequence again.
588                  */
589                 if (CE_HasLabel (E)) {
590                     CS_MoveLabels (S, E, L[0]);
591                 }
592
593             }
594
595             ++Changes;
596         }
597
598         /* Next entry */
599         ++I;
600
601     }
602
603     /* Return the number of changes made */
604     return Changes;
605 }
606
607
608
609 unsigned OptCmp4 (CodeSeg* S)
610 /* Optimize compares of local variables:
611  *
612  *      ldy     #o
613  *      lda     (sp),y
614  *      tax
615  *      dey
616  *      lda     (sp),y
617  *      cpx     #a
618  *      bne     L1
619  *      cmp     #b
620  *      jne/jeq L2
621  */
622 {
623     unsigned Changes = 0;
624
625     /* Walk over the entries */
626     unsigned I = 0;
627     while (I < CS_GetEntryCount (S)) {
628
629         CodeEntry* L[9];
630
631         /* Check for the sequence */
632         if (IsLocalLoad16 (S, I, L, 9) && IsImmCmp16 (L+5)) {
633
634             if ((L[8]->Info & OF_FBRA) != 0 && L[5]->Num == 0 && L[7]->Num == 0) {
635
636                 /* The value is zero, we may use the simple code version:
637                  *      ldy     #o
638                  *      lda     (sp),y
639                  *      ldy     #o-1
640                  *      ora     (sp),y
641                  *      jne/jeq ...
642                  */
643                 CE_ReplaceOPC (L[4], OP65_ORA);
644                 CS_DelEntries (S, I+5, 3);   /* cpx/bne/cmp */
645                 CS_DelEntry (S, I+2);        /* tax */
646
647             } else {
648
649                 /* Change the code to just use the A register. Move the load
650                  * of the low byte after the first branch if possible:
651                  *
652                  *      ldy     #o
653                  *      lda     (sp),y
654                  *      cmp     #a
655                  *      bne     L1
656                  *      ldy     #o-1
657                  *      lda     (sp),y
658                  *      cmp     #b
659                  *      jne/jeq ...
660                  */
661                 CS_DelEntry (S, I+2);             /* tax */
662                 CE_ReplaceOPC (L[5], OP65_CMP);   /* cpx -> cmp */
663                 CS_MoveEntry (S, I+4, I+2);       /* cmp */
664                 CS_MoveEntry (S, I+5, I+3);       /* bne */
665
666             }
667
668             ++Changes;
669         }
670
671         /* Next entry */
672         ++I;
673
674     }
675
676     /* Return the number of changes made */
677     return Changes;
678 }
679
680
681
682 unsigned OptCmp5 (CodeSeg* S)
683 /* Search for calls to compare subroutines followed by a conditional branch
684  * and replace them by cheaper versions, since the branch means that the
685  * boolean value returned by these routines is not needed (we may also check
686  * that explicitly, but for the current code generator it is always true).
687  */
688 {
689     unsigned Changes = 0;
690
691     /* Walk over the entries */
692     unsigned I = 0;
693     while (I < CS_GetEntryCount (S)) {
694
695         CodeEntry* N;
696         cmp_t Cond;
697
698         /* Get next entry */
699         CodeEntry* E = CS_GetEntry (S, I);
700
701         /* Check for the sequence */
702         if (E->OPC == OP65_JSR                          &&
703             (Cond = FindTosCmpCond (E->Arg)) != CMP_INV &&
704             (N = CS_GetNextEntry (S, I)) != 0           &&
705             (N->Info & OF_ZBRA) != 0                    &&
706             !CE_HasLabel (N)) {
707
708             /* The tos... functions will return a boolean value in a/x and
709              * the Z flag says if this value is zero or not. We will call
710              * a cheaper subroutine instead, one that does not return a
711              * boolean value but only valid flags. Note: jeq jumps if
712              * the condition is not met, jne jumps if the condition is met.
713              * Invert the code if we jump on condition not met.
714              */
715             if (GetBranchCond (N->OPC) == BC_EQ) {
716                 /* Jumps if condition false, invert condition */
717                 Cond = CmpInvertTab [Cond];
718             }
719
720             /* Replace the subroutine call. */
721             E = NewCodeEntry (OP65_JSR, AM65_ABS, "tosicmp", 0, E->LI);
722             CS_InsertEntry (S, E, I+1);
723             CS_DelEntry (S, I);
724
725             /* Replace the conditional branch */
726             ReplaceCmp (S, I+1, Cond);
727
728             /* Remember, we had changes */
729             ++Changes;
730
731         }
732
733         /* Next entry */
734         ++I;
735
736     }
737
738     /* Return the number of changes made */
739     return Changes;
740 }
741
742
743
744 unsigned OptCmp6 (CodeSeg* S)
745 /* Search for a sequence ldx/txa/branch and remove the txa if A is not
746  * used later.
747  */
748 {
749     unsigned Changes = 0;
750
751     /* Walk over the entries */
752     unsigned I = 0;
753     while (I < CS_GetEntryCount (S)) {
754
755         CodeEntry* L[2];
756
757         /* Get next entry */
758         CodeEntry* E = CS_GetEntry (S, I);
759
760         /* Check for the sequence */
761         if ((E->OPC == OP65_LDX)                        &&
762             CS_GetEntries (S, L, I+1, 2)                &&
763             L[0]->OPC == OP65_TXA                       &&
764             !CE_HasLabel (L[0])                         &&
765             (L[1]->Info & OF_FBRA) != 0                 &&
766             !CE_HasLabel (L[1])                         &&
767             !RegAUsed (S, I+3)) {
768
769             /* Remove the txa */
770             CS_DelEntry (S, I+1);
771
772             /* Remember, we had changes */
773             ++Changes;
774
775         }
776
777         /* Next entry */
778         ++I;
779
780     }
781
782     /* Return the number of changes made */
783     return Changes;
784 }
785
786
787
788 unsigned OptCmp7 (CodeSeg* S)
789 /* Check for register compares where the contents of the register and therefore
790  * the result of the compare is known.
791  */
792 {
793     unsigned Changes = 0;
794     unsigned I;
795
796     /* Generate register info for this step */
797     CS_GenRegInfo (S);
798
799     /* Walk over the entries */
800     I = 0;
801     while (I < CS_GetEntryCount (S)) {
802
803         int RegVal;
804
805         /* Get next entry */
806         CodeEntry* E = CS_GetEntry (S, I);
807
808         /* Check for a compare against an immediate value */
809         if ((E->Info & OF_CMP) != 0           &&
810             (RegVal = GetCmpRegVal (E)) >= 0  &&
811             CE_KnownImm (E)) {
812
813             /* We are able to evaluate the compare at compile time. Check if
814              * one or more branches are ahead.
815              */
816             unsigned JumpsChanged = 0;
817             CodeEntry* N;
818             while ((N = CS_GetNextEntry (S, I)) != 0 &&   /* Followed by something.. */
819                    (N->Info & OF_CBRA) != 0          &&   /* ..that is a cond branch.. */
820                    !CE_HasLabel (N)) {                    /* ..and has no label */
821
822                 /* Evaluate the branch condition */
823                 int Cond;
824                 switch (GetBranchCond (N->OPC)) {
825                     case BC_CC:
826                         Cond = ((unsigned char)RegVal) < ((unsigned char)E->Num);
827                         break;
828
829                     case BC_CS:
830                         Cond = ((unsigned char)RegVal) >= ((unsigned char)E->Num);
831                         break;
832
833                     case BC_EQ:
834                         Cond = ((unsigned char)RegVal) == ((unsigned char)E->Num);
835                         break;
836
837                     case BC_MI:
838                         Cond = ((signed char)RegVal) < ((signed char)E->Num);
839                         break;
840
841                     case BC_NE:
842                         Cond = ((unsigned char)RegVal) != ((unsigned char)E->Num);
843                         break;
844
845                     case BC_PL:
846                         Cond = ((signed char)RegVal) >= ((signed char)E->Num);
847                         break;
848
849                     case BC_VC:
850                     case BC_VS:
851                         /* Not set by the compare operation, bail out (Note:
852                          * Just skipping anything here is rather stupid, but
853                          * the sequence is never generated by the compiler,
854                          * so it's quite safe to skip).
855                          */
856                         goto NextEntry;
857
858                     default:
859                         Internal ("Unknown branch condition");
860
861                 }
862
863                 /* If the condition is false, we may remove the jump. Otherwise
864                  * the branch will always be taken, so we may replace it by a
865                  * jump (and bail out).
866                  */
867                 if (!Cond) {
868                     CS_DelEntry (S, I+1);
869                 } else {
870                     CodeLabel* L = N->JumpTo;
871                     const char* LabelName = L? L->Name : N->Arg;
872                     CodeEntry* X = NewCodeEntry (OP65_JMP, AM65_BRA, LabelName, L, N->LI);
873                     CS_InsertEntry (S, X, I+2);
874                     CS_DelEntry (S, I+1);
875                 }
876
877                 /* Remember, we had changes */
878                 ++JumpsChanged;
879                 ++Changes;
880             }
881
882             /* If we have made changes above, we may also remove the compare */
883             if (JumpsChanged) {
884                 CS_DelEntry (S, I);
885             }
886
887         }
888
889 NextEntry:
890         /* Next entry */
891         ++I;
892
893     }
894
895     /* Free register info */
896     CS_FreeRegInfo (S);
897
898     /* Return the number of changes made */
899     return Changes;
900 }
901
902
903