]> git.sur5r.net Git - cc65/blob - src/cc65/coptcmp.c
More splitting
[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 (CodeSeg* S, 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             L[0]->AM == AM65_IMM                         &&
328             (L[0]->Flags & CEF_NUMARG) != 0              &&
329             CS_GetEntries (S, L+1, Index+1, Count-1)     &&
330             IsSpLoad (L[1])                              &&
331             !CE_HasLabel (L[1])                          &&
332             L[2]->OPC == OP65_TAX                        &&
333             !CE_HasLabel (L[2])                          &&
334             L[3]->OPC == OP65_DEY                        &&
335             !CE_HasLabel (L[3])                          &&
336             IsSpLoad (L[4])                              &&
337             !CE_HasLabel (L[4]));
338 }
339
340
341
342 /*****************************************************************************/
343 /*             Remove calls to the bool transformer subroutines              */
344 /*****************************************************************************/
345
346
347
348 unsigned OptBoolTrans (CodeSeg* S)
349 /* Try to remove the call to boolean transformer routines where the call is
350  * not really needed.
351  */
352 {
353     unsigned Changes = 0;
354
355     /* Walk over the entries */
356     unsigned I = 0;
357     while (I < CS_GetEntryCount (S)) {
358
359         CodeEntry* N;
360         cmp_t Cond;
361
362         /* Get next entry */
363         CodeEntry* E = CS_GetEntry (S, I);
364
365         /* Check for a boolean transformer */
366         if (E->OPC == OP65_JSR                           &&
367             (Cond = FindBoolCmpCond (E->Arg)) != CMP_INV &&
368             (N = CS_GetNextEntry (S, I)) != 0        &&
369             (N->Info & OF_ZBRA) != 0) {
370
371             /* Make the boolean transformer unnecessary by changing the
372              * the conditional jump to evaluate the condition flags that
373              * are set after the compare directly. Note: jeq jumps if
374              * the condition is not met, jne jumps if the condition is met.
375              * Invert the code if we jump on condition not met.
376              */
377             if (GetBranchCond (N->OPC) == BC_EQ) {
378                 /* Jumps if condition false, invert condition */
379                 Cond = CmpInvertTab [Cond];
380             }
381
382             /* Check if we can replace the code by something better */
383             ReplaceCmp (S, I+1, Cond);
384
385             /* Remove the call to the bool transformer */
386             CS_DelEntry (S, I);
387
388             /* Remember, we had changes */
389             ++Changes;
390
391         }
392
393         /* Next entry */
394         ++I;
395
396     }
397
398     /* Return the number of changes made */
399     return Changes;
400 }
401
402
403
404 /*****************************************************************************/
405 /*                        Optimizations for compares                         */
406 /*****************************************************************************/
407
408
409
410 unsigned OptCmp1 (CodeSeg* S)
411 /* Search for the sequence
412  *
413  *      stx     xx
414  *      stx     tmp1
415  *      ora     tmp1
416  *
417  * and replace it by
418  *
419  *      stx     xx
420  *      ora     xx
421  */
422 {
423     unsigned Changes = 0;
424
425     /* Walk over the entries */
426     unsigned I = 0;
427     while (I < CS_GetEntryCount (S)) {
428
429         CodeEntry* L[2];
430
431         /* Get next entry */
432         CodeEntry* E = CS_GetEntry (S, I);
433
434         /* Check for the sequence */
435         if (E->OPC == OP65_STX                  &&
436             CS_GetEntries (S, L, I+1, 2)        &&
437             L[0]->OPC == OP65_STX               &&
438             strcmp (L[0]->Arg, "tmp1") == 0     &&
439             !CE_HasLabel (L[0])                 &&
440             L[1]->OPC == OP65_ORA               &&
441             strcmp (L[1]->Arg, "tmp1") == 0     &&
442             !CE_HasLabel (L[1])) {
443
444             /* Remove the remaining instructions */
445             CS_DelEntries (S, I+1, 2);
446
447             /* Insert the ora instead */
448             CS_InsertEntry (S, NewCodeEntry (OP65_ORA, E->AM, E->Arg, 0, E->LI), I+1);
449
450             /* Remember, we had changes */
451             ++Changes;
452
453         }
454
455         /* Next entry */
456         ++I;
457
458     }
459
460     /* Return the number of changes made */
461     return Changes;
462 }
463
464
465
466 unsigned OptCmp2 (CodeSeg* S)
467 /* Search for
468  *
469  *      lda/and/ora/eor ...
470  *      cmp #$00
471  *      jeq/jne
472  * or
473  *      lda/and/ora/eor ...
474  *      cmp #$00
475  *      jsr boolxx
476  *
477  * and remove the cmp.
478  */
479 {
480     unsigned Changes = 0;
481
482     /* Walk over the entries */
483     unsigned I = 0;
484     while (I < CS_GetEntryCount (S)) {
485
486         CodeEntry* L[2];
487
488         /* Get next entry */
489         CodeEntry* E = CS_GetEntry (S, I);
490
491         /* Check for the sequence */
492         if ((E->OPC == OP65_ADC ||
493              E->OPC == OP65_AND ||
494              E->OPC == OP65_DEA ||
495              E->OPC == OP65_EOR ||
496              E->OPC == OP65_INA ||
497              E->OPC == OP65_LDA ||
498              E->OPC == OP65_ORA ||
499              E->OPC == OP65_PLA ||
500              E->OPC == OP65_SBC ||
501              E->OPC == OP65_TXA ||
502              E->OPC == OP65_TYA)                       &&
503             CS_GetEntries (S, L, I+1, 2)               &&
504             IsCmpToZero (L[0])                         &&
505             !CE_HasLabel (L[0])                        &&
506             ((L[1]->Info & OF_FBRA) != 0         ||
507              (L[1]->OPC == OP65_JSR        &&
508               FindBoolCmpCond (L[1]->Arg) != CMP_INV)) &&
509             !CE_HasLabel (L[1])) {
510
511             /* Remove the compare */
512             CS_DelEntry (S, I+1);
513
514             /* Remember, we had changes */
515             ++Changes;
516
517         }
518
519         /* Next entry */
520         ++I;
521
522     }
523
524     /* Return the number of changes made */
525     return Changes;
526 }
527
528
529
530 unsigned OptCmp3 (CodeSeg* S)
531 /* Search for
532  *
533  *      lda     x
534  *      ldx     y
535  *      cpx     #a
536  *      bne     L1
537  *      cmp     #b
538  *      jne/jeq L2
539  *
540  * If a is zero, we may remove the compare. If a and b are both zero, we may
541  * replace it by the sequence
542  *
543  *      lda     x
544  *      ora     x+1
545  *      jne/jeq ...
546  *
547  * L1 may be either the label at the branch instruction, or the target label
548  * of this instruction.
549  */
550 {
551     unsigned Changes = 0;
552
553     /* Walk over the entries */
554     unsigned I = 0;
555     while (I < CS_GetEntryCount (S)) {
556
557         CodeEntry* L[5];
558
559         /* Get next entry */
560         CodeEntry* E = CS_GetEntry (S, I);
561
562         /* Check for the sequence */
563         if (E->OPC == OP65_LDA               &&
564             CS_GetEntries (S, L, I+1, 5) &&
565             L[0]->OPC == OP65_LDX            &&
566             !CE_HasLabel (L[0])              &&
567             IsImmCmp16 (S, L+1)) {
568
569             if (L[1]->Num == 0 && L[3]->Num == 0) {
570                 /* The value is zero, we may use the simple code version. */
571                 CE_ReplaceOPC (L[0], OP65_ORA);
572                 CS_DelEntries (S, I+2, 3);
573             } else {
574                 /* Move the lda instruction after the first branch. This will
575                  * improve speed, since the load is delayed after the first
576                  * test.
577                  */
578                 CS_MoveEntry (S, I, I+4);
579
580                 /* We will replace the ldx/cpx by lda/cmp */
581                 CE_ReplaceOPC (L[0], OP65_LDA);
582                 CE_ReplaceOPC (L[1], OP65_CMP);
583
584                 /* Beware: If the first LDA instruction had a label, we have
585                  * to move this label to the top of the sequence again.
586                  */
587                 if (CE_HasLabel (E)) {
588                     CS_MoveLabels (S, E, L[0]);
589                 }
590
591             }
592
593             ++Changes;
594         }
595
596         /* Next entry */
597         ++I;
598
599     }
600
601     /* Return the number of changes made */
602     return Changes;
603 }
604
605
606
607 unsigned OptCmp4 (CodeSeg* S)
608 /* Optimize compares of local variables:
609  *
610  *      ldy     #o
611  *      lda     (sp),y
612  *      tax
613  *      dey
614  *      lda     (sp),y
615  *      cpx     #a
616  *      bne     L1
617  *      cmp     #b
618  *      jne/jeq L2
619  */
620 {
621     unsigned Changes = 0;
622
623     /* Walk over the entries */
624     unsigned I = 0;
625     while (I < CS_GetEntryCount (S)) {
626
627         CodeEntry* L[9];
628
629         /* Check for the sequence */
630         if (IsLocalLoad16 (S, I, L, 9) && IsImmCmp16 (S, L+5)) {
631
632             if (L[5]->Num == 0 && L[7]->Num == 0) {
633
634                 /* The value is zero, we may use the simple code version:
635                  *      ldy     #o
636                  *      lda     (sp),y
637                  *      dey
638                  *      ora     (sp),y
639                  *      jne/jeq ...
640                  */
641                 CE_ReplaceOPC (L[4], OP65_ORA);
642                 CS_DelEntries (S, I+5, 3);   /* cpx/bne/cmp */
643                 CS_DelEntry (S, I+2);        /* tax */
644
645             } else {
646
647                 /* Change the code to just use the A register. Move the load
648                  * of the low byte after the first branch if possible:
649                  *
650                  *      ldy     #o
651                  *      lda     (sp),y
652                  *      cmp     #a
653                  *      bne     L1
654                  *      dey
655                  *      lda     (sp),y
656                  *      cmp     #b
657                  *      jne/jeq ...
658                  */
659                 CS_DelEntry (S, I+2);             /* tax */
660                 CE_ReplaceOPC (L[5], OP65_CMP);   /* cpx -> cmp */
661                 CS_MoveEntry (S, I+4, I+2);       /* cmp */
662                 CS_MoveEntry (S, I+5, I+3);       /* bne */
663
664             }
665
666             ++Changes;
667         }
668
669         /* Next entry */
670         ++I;
671
672     }
673
674     /* Return the number of changes made */
675     return Changes;
676 }
677
678
679
680 unsigned OptCmp5 (CodeSeg* S)
681 /* Search for calls to compare subroutines followed by a conditional branch
682  * and replace them by cheaper versions, since the branch means that the
683  * boolean value returned by these routines is not needed (we may also check
684  * that explicitly, but for the current code generator it is always true).
685  */
686 {
687     unsigned Changes = 0;
688
689     /* Walk over the entries */
690     unsigned I = 0;
691     while (I < CS_GetEntryCount (S)) {
692
693         CodeEntry* N;
694         cmp_t Cond;
695
696         /* Get next entry */
697         CodeEntry* E = CS_GetEntry (S, I);
698
699         /* Check for the sequence */
700         if (E->OPC == OP65_JSR                          &&
701             (Cond = FindTosCmpCond (E->Arg)) != CMP_INV &&
702             (N = CS_GetNextEntry (S, I)) != 0           &&
703             (N->Info & OF_ZBRA) != 0                    &&
704             !CE_HasLabel (N)) {
705
706             /* The tos... functions will return a boolean value in a/x and
707              * the Z flag says if this value is zero or not. We will call
708              * a cheaper subroutine instead, one that does not return a
709              * boolean value but only valid flags. Note: jeq jumps if
710              * the condition is not met, jne jumps if the condition is met.
711              * Invert the code if we jump on condition not met.
712              */
713             if (GetBranchCond (N->OPC) == BC_EQ) {
714                 /* Jumps if condition false, invert condition */
715                 Cond = CmpInvertTab [Cond];
716             }
717
718             /* Replace the subroutine call. */
719             E = NewCodeEntry (OP65_JSR, AM65_ABS, "tosicmp", 0, E->LI);
720             CS_InsertEntry (S, E, I+1);
721             CS_DelEntry (S, I);
722
723             /* Replace the conditional branch */
724             ReplaceCmp (S, I+1, Cond);
725
726             /* Remember, we had changes */
727             ++Changes;
728
729         }
730
731         /* Next entry */
732         ++I;
733
734     }
735
736     /* Return the number of changes made */
737     return Changes;
738 }
739
740
741
742 unsigned OptCmp6 (CodeSeg* S)
743 /* Search for a sequence ldx/txa/branch and remove the txa if A is not
744  * used later.
745  */
746 {
747     unsigned Changes = 0;
748
749     /* Walk over the entries */
750     unsigned I = 0;
751     while (I < CS_GetEntryCount (S)) {
752
753         CodeEntry* L[2];
754
755         /* Get next entry */
756         CodeEntry* E = CS_GetEntry (S, I);
757
758         /* Check for the sequence */
759         if ((E->OPC == OP65_LDX)                        &&
760             CS_GetEntries (S, L, I+1, 2)                &&
761             L[0]->OPC == OP65_TXA                       &&
762             !CE_HasLabel (L[0])                         &&
763             (L[1]->Info & OF_FBRA) != 0                 &&
764             !CE_HasLabel (L[1])                         &&
765             !RegAUsed (S, I+3)) {
766
767             /* Remove the txa */
768             CS_DelEntry (S, I+1);
769
770             /* Remember, we had changes */
771             ++Changes;
772
773         }
774
775         /* Next entry */
776         ++I;
777
778     }
779
780     /* Return the number of changes made */
781     return Changes;
782 }
783
784
785
786 unsigned OptCmp7 (CodeSeg* S)
787 /* Check for register compares where the contents of the register and therefore
788  * the result of the compare is known.
789  */
790 {
791     unsigned Changes = 0;
792     unsigned I;
793
794     /* Generate register info for this step */
795     CS_GenRegInfo (S);
796
797     /* Walk over the entries */
798     I = 0;
799     while (I < CS_GetEntryCount (S)) {
800
801         int RegVal;
802
803         /* Get next entry */
804         CodeEntry* E = CS_GetEntry (S, I);
805
806         /* Check for a compare against an immediate value */
807         if ((E->Info & OF_CMP) != 0           &&
808             (RegVal = GetCmpRegVal (E)) >= 0  &&
809             CE_KnownImm (E)) {
810
811             /* We are able to evaluate the compare at compile time. Check if
812              * one or more branches are ahead.
813              */
814             unsigned JumpsChanged = 0;
815             CodeEntry* N;
816             while ((N = CS_GetNextEntry (S, I)) != 0 &&   /* Followed by something.. */
817                    (N->Info & OF_CBRA) != 0          &&   /* ..that is a cond branch.. */
818                    !CE_HasLabel (N)) {                    /* ..and has no label */
819
820                 /* Evaluate the branch condition */
821                 int Cond;
822                 switch (GetBranchCond (N->OPC)) {
823                     case BC_CC:
824                         Cond = ((unsigned char)RegVal) < ((unsigned char)E->Num);
825                         break;
826
827                     case BC_CS:
828                         Cond = ((unsigned char)RegVal) >= ((unsigned char)E->Num);
829                         break;
830
831                     case BC_EQ:
832                         Cond = ((unsigned char)RegVal) == ((unsigned char)E->Num);
833                         break;
834
835                     case BC_MI:
836                         Cond = ((signed char)RegVal) < ((signed char)E->Num);
837                         break;
838
839                     case BC_NE:
840                         Cond = ((unsigned char)RegVal) != ((unsigned char)E->Num);
841                         break;
842
843                     case BC_PL:
844                         Cond = ((signed char)RegVal) >= ((signed char)E->Num);
845                         break;
846
847                     case BC_VC:
848                     case BC_VS:
849                         /* Not set by the compare operation, bail out (Note:
850                          * Just skipping anything here is rather stupid, but
851                          * the sequence is never generated by the compiler,
852                          * so it's quite safe to skip).
853                          */
854                         goto NextEntry;
855
856                     default:
857                         Internal ("Unknown branch condition");
858
859                 }
860
861                 /* If the condition is false, we may remove the jump. Otherwise
862                  * the branch will always be taken, so we may replace it by a
863                  * jump (and bail out).
864                  */
865                 if (!Cond) {
866                     CS_DelEntry (S, I+1);
867                 } else {
868                     CodeLabel* L = N->JumpTo;
869                     CodeEntry* X = NewCodeEntry (OP65_JMP, AM65_BRA, L->Name, L, N->LI);
870                     CS_InsertEntry (S, X, I+2);
871                     CS_DelEntry (S, I+1);
872                 }
873
874                 /* Remember, we had changes */
875                 ++JumpsChanged;
876                 ++Changes;
877             }
878
879             /* If we have made changes above, we may also remove the compare */
880             if (JumpsChanged) {
881                 CS_DelEntry (S, I);
882             }
883
884         }
885
886 NextEntry:
887         /* Next entry */
888         ++I;
889
890     }
891
892     /* Free register info */
893     CS_FreeRegInfo (S);
894
895     /* Return the number of changes made */
896     return Changes;
897 }
898
899
900