]> git.sur5r.net Git - cc65/blob - src/cc65/coptcmp.c
Handle intermediate access to local variables in the stack op optimizations.
[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_ZBRA) != 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  *      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
570             if (L[1]->Num == 0 && L[3]->Num == 0) {
571                 /* The value is zero, we may use the simple code version. */
572                 CE_ReplaceOPC (L[0], OP65_ORA);
573                 CS_DelEntries (S, I+2, 3);
574             } else {
575                 /* Move the lda instruction after the first branch. This will
576                  * improve speed, since the load is delayed after the first
577                  * test.
578                  */
579                 CS_MoveEntry (S, I, I+4);
580
581                 /* We will replace the ldx/cpx by lda/cmp */
582                 CE_ReplaceOPC (L[0], OP65_LDA);
583                 CE_ReplaceOPC (L[1], OP65_CMP);
584
585                 /* Beware: If the first LDA instruction had a label, we have
586                  * to move this label to the top of the sequence again.
587                  */
588                 if (CE_HasLabel (E)) {
589                     CS_MoveLabels (S, E, L[0]);
590                 }
591
592             }
593
594             ++Changes;
595         }
596
597         /* Next entry */
598         ++I;
599
600     }
601
602     /* Return the number of changes made */
603     return Changes;
604 }
605
606
607
608 unsigned OptCmp4 (CodeSeg* S)
609 /* Optimize compares of local variables:
610  *
611  *      ldy     #o
612  *      lda     (sp),y
613  *      tax
614  *      dey
615  *      lda     (sp),y
616  *      cpx     #a
617  *      bne     L1
618  *      cmp     #b
619  *      jne/jeq L2
620  */
621 {
622     unsigned Changes = 0;
623
624     /* Walk over the entries */
625     unsigned I = 0;
626     while (I < CS_GetEntryCount (S)) {
627
628         CodeEntry* L[9];
629
630         /* Check for the sequence */
631         if (IsLocalLoad16 (S, I, L, 9) && IsImmCmp16 (L+5)) {
632
633             if (L[5]->Num == 0 && L[7]->Num == 0) {
634
635                 /* The value is zero, we may use the simple code version:
636                  *      ldy     #o
637                  *      lda     (sp),y
638                  *      ldy     #o-1
639                  *      ora     (sp),y
640                  *      jne/jeq ...
641                  */
642                 CE_ReplaceOPC (L[4], OP65_ORA);
643                 CS_DelEntries (S, I+5, 3);   /* cpx/bne/cmp */
644                 CS_DelEntry (S, I+2);        /* tax */
645
646             } else {
647
648                 /* Change the code to just use the A register. Move the load
649                  * of the low byte after the first branch if possible:
650                  *
651                  *      ldy     #o
652                  *      lda     (sp),y
653                  *      cmp     #a
654                  *      bne     L1
655                  *      ldy     #o-1
656                  *      lda     (sp),y
657                  *      cmp     #b
658                  *      jne/jeq ...
659                  */
660                 CS_DelEntry (S, I+2);             /* tax */
661                 CE_ReplaceOPC (L[5], OP65_CMP);   /* cpx -> cmp */
662                 CS_MoveEntry (S, I+4, I+2);       /* cmp */
663                 CS_MoveEntry (S, I+5, I+3);       /* bne */
664
665             }
666
667             ++Changes;
668         }
669
670         /* Next entry */
671         ++I;
672
673     }
674
675     /* Return the number of changes made */
676     return Changes;
677 }
678
679
680
681 unsigned OptCmp5 (CodeSeg* S)
682 /* Search for calls to compare subroutines followed by a conditional branch
683  * and replace them by cheaper versions, since the branch means that the
684  * boolean value returned by these routines is not needed (we may also check
685  * that explicitly, but for the current code generator it is always true).
686  */
687 {
688     unsigned Changes = 0;
689
690     /* Walk over the entries */
691     unsigned I = 0;
692     while (I < CS_GetEntryCount (S)) {
693
694         CodeEntry* N;
695         cmp_t Cond;
696
697         /* Get next entry */
698         CodeEntry* E = CS_GetEntry (S, I);
699
700         /* Check for the sequence */
701         if (E->OPC == OP65_JSR                          &&
702             (Cond = FindTosCmpCond (E->Arg)) != CMP_INV &&
703             (N = CS_GetNextEntry (S, I)) != 0           &&
704             (N->Info & OF_ZBRA) != 0                    &&
705             !CE_HasLabel (N)) {
706
707             /* The tos... functions will return a boolean value in a/x and
708              * the Z flag says if this value is zero or not. We will call
709              * a cheaper subroutine instead, one that does not return a
710              * boolean value but only valid flags. Note: jeq jumps if
711              * the condition is not met, jne jumps if the condition is met.
712              * Invert the code if we jump on condition not met.
713              */
714             if (GetBranchCond (N->OPC) == BC_EQ) {
715                 /* Jumps if condition false, invert condition */
716                 Cond = CmpInvertTab [Cond];
717             }
718
719             /* Replace the subroutine call. */
720             E = NewCodeEntry (OP65_JSR, AM65_ABS, "tosicmp", 0, E->LI);
721             CS_InsertEntry (S, E, I+1);
722             CS_DelEntry (S, I);
723
724             /* Replace the conditional branch */
725             ReplaceCmp (S, I+1, Cond);
726
727             /* Remember, we had changes */
728             ++Changes;
729
730         }
731
732         /* Next entry */
733         ++I;
734
735     }
736
737     /* Return the number of changes made */
738     return Changes;
739 }
740
741
742
743 unsigned OptCmp6 (CodeSeg* S)
744 /* Search for a sequence ldx/txa/branch and remove the txa if A is not
745  * used later.
746  */
747 {
748     unsigned Changes = 0;
749
750     /* Walk over the entries */
751     unsigned I = 0;
752     while (I < CS_GetEntryCount (S)) {
753
754         CodeEntry* L[2];
755
756         /* Get next entry */
757         CodeEntry* E = CS_GetEntry (S, I);
758
759         /* Check for the sequence */
760         if ((E->OPC == OP65_LDX)                        &&
761             CS_GetEntries (S, L, I+1, 2)                &&
762             L[0]->OPC == OP65_TXA                       &&
763             !CE_HasLabel (L[0])                         &&
764             (L[1]->Info & OF_FBRA) != 0                 &&
765             !CE_HasLabel (L[1])                         &&
766             !RegAUsed (S, I+3)) {
767
768             /* Remove the txa */
769             CS_DelEntry (S, I+1);
770
771             /* Remember, we had changes */
772             ++Changes;
773
774         }
775
776         /* Next entry */
777         ++I;
778
779     }
780
781     /* Return the number of changes made */
782     return Changes;
783 }
784
785
786
787 unsigned OptCmp7 (CodeSeg* S)
788 /* Check for register compares where the contents of the register and therefore
789  * the result of the compare is known.
790  */
791 {
792     unsigned Changes = 0;
793     unsigned I;
794
795     /* Generate register info for this step */
796     CS_GenRegInfo (S);
797
798     /* Walk over the entries */
799     I = 0;
800     while (I < CS_GetEntryCount (S)) {
801
802         int RegVal;
803
804         /* Get next entry */
805         CodeEntry* E = CS_GetEntry (S, I);
806
807         /* Check for a compare against an immediate value */
808         if ((E->Info & OF_CMP) != 0           &&
809             (RegVal = GetCmpRegVal (E)) >= 0  &&
810             CE_KnownImm (E)) {
811
812             /* We are able to evaluate the compare at compile time. Check if
813              * one or more branches are ahead.
814              */
815             unsigned JumpsChanged = 0;
816             CodeEntry* N;
817             while ((N = CS_GetNextEntry (S, I)) != 0 &&   /* Followed by something.. */
818                    (N->Info & OF_CBRA) != 0          &&   /* ..that is a cond branch.. */
819                    !CE_HasLabel (N)) {                    /* ..and has no label */
820
821                 /* Evaluate the branch condition */
822                 int Cond;
823                 switch (GetBranchCond (N->OPC)) {
824                     case BC_CC:
825                         Cond = ((unsigned char)RegVal) < ((unsigned char)E->Num);
826                         break;
827
828                     case BC_CS:
829                         Cond = ((unsigned char)RegVal) >= ((unsigned char)E->Num);
830                         break;
831
832                     case BC_EQ:
833                         Cond = ((unsigned char)RegVal) == ((unsigned char)E->Num);
834                         break;
835
836                     case BC_MI:
837                         Cond = ((signed char)RegVal) < ((signed char)E->Num);
838                         break;
839
840                     case BC_NE:
841                         Cond = ((unsigned char)RegVal) != ((unsigned char)E->Num);
842                         break;
843
844                     case BC_PL:
845                         Cond = ((signed char)RegVal) >= ((signed char)E->Num);
846                         break;
847
848                     case BC_VC:
849                     case BC_VS:
850                         /* Not set by the compare operation, bail out (Note:
851                          * Just skipping anything here is rather stupid, but
852                          * the sequence is never generated by the compiler,
853                          * so it's quite safe to skip).
854                          */
855                         goto NextEntry;
856
857                     default:
858                         Internal ("Unknown branch condition");
859
860                 }
861
862                 /* If the condition is false, we may remove the jump. Otherwise
863                  * the branch will always be taken, so we may replace it by a
864                  * jump (and bail out).
865                  */
866                 if (!Cond) {
867                     CS_DelEntry (S, I+1);
868                 } else {
869                     CodeLabel* L = N->JumpTo;
870                     CodeEntry* X = NewCodeEntry (OP65_JMP, AM65_BRA, L->Name, L, N->LI);
871                     CS_InsertEntry (S, X, I+2);
872                     CS_DelEntry (S, I+1);
873                 }
874
875                 /* Remember, we had changes */
876                 ++JumpsChanged;
877                 ++Changes;
878             }
879
880             /* If we have made changes above, we may also remove the compare */
881             if (JumpsChanged) {
882                 CS_DelEntry (S, I);
883             }
884
885         }
886
887 NextEntry:
888         /* Next entry */
889         ++I;
890
891     }
892
893     /* Free register info */
894     CS_FreeRegInfo (S);
895
896     /* Return the number of changes made */
897     return Changes;
898 }
899
900
901