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