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