]> git.sur5r.net Git - cc65/blob - src/cc65/coptptrload.c
fixed optimization bug where array index is 16-bit, e.g. arr16[i & 0x7f7f]
[cc65] / src / cc65 / coptptrload.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                               coptptrload.c                               */
4 /*                                                                           */
5 /*                      Optimize loads through pointers                      */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2001-2009 Ullrich von Bassewitz                                       */
10 /*               Roemerstrasse 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 /* common */
39 #include "xmalloc.h"
40
41 /* cc65 */
42 #include "codeent.h"
43 #include "codeinfo.h"
44 #include "coptptrload.h"
45
46
47
48 /*****************************************************************************/
49 /*                                   Code                                    */
50 /*****************************************************************************/
51
52
53
54 unsigned OptPtrLoad1 (CodeSeg* S)
55 /* Search for the sequence:
56 **
57 **      clc
58 **      adc     xxx
59 **      tay
60 **      txa
61 **      adc     yyy
62 **      tax
63 **      tya
64 **      ldy     #$00
65 **      jsr     ldauidx
66 **
67 ** and replace it by:
68 **
69 **      sta     ptr1
70 **      txa
71 **      clc
72 **      adc     yyy
73 **      sta     ptr1+1
74 **      ldy     xxx
75 **      ldx     #$00
76 **      lda     (ptr1),y
77 */
78 {
79     unsigned Changes = 0;
80
81     /* Walk over the entries */
82     unsigned I = 0;
83     while (I < CS_GetEntryCount (S)) {
84
85         CodeEntry* L[9];
86
87         /* Get next entry */
88         L[0] = CS_GetEntry (S, I);
89
90         /* Check for the sequence */
91         if (L[0]->OPC == OP65_CLC               &&
92             CS_GetEntries (S, L+1, I+1, 8)      &&
93             L[1]->OPC == OP65_ADC               &&
94             (L[1]->AM == AM65_ABS          ||
95              L[1]->AM == AM65_ZP           ||
96              L[1]->AM == AM65_IMM)              &&
97             L[2]->OPC == OP65_TAY               &&
98             L[3]->OPC == OP65_TXA               &&
99             L[4]->OPC == OP65_ADC               &&
100             L[5]->OPC == OP65_TAX               &&
101             L[6]->OPC == OP65_TYA               &&
102             L[7]->OPC == OP65_LDY               &&
103             CE_IsKnownImm (L[7], 0)             &&
104             CE_IsCallTo (L[8], "ldauidx")       &&
105             !CS_RangeHasLabel (S, I+1, 8)) {
106
107             CodeEntry* X;
108             CodeEntry* P;
109
110             /* Track the insertion point */
111             unsigned IP = I+9;
112
113             /* sta ptr1 */
114             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[2]->LI);
115             CS_InsertEntry (S, X, IP++);
116
117             /* If the instruction before the clc is a ldx, replace the
118             ** txa by an lda with the same location of the ldx. Otherwise
119             ** transfer the value in X to A.
120             */
121             if ((P = CS_GetPrevEntry (S, I)) != 0 &&
122                 P->OPC == OP65_LDX                &&
123                 !CE_HasLabel (P)) {
124                 X = NewCodeEntry (OP65_LDA, P->AM, P->Arg, 0, P->LI);
125             } else {
126                 X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, L[3]->LI);
127             }
128             CS_InsertEntry (S, X, IP++);
129
130             /* clc */
131             X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[0]->LI);
132             CS_InsertEntry (S, X, IP++);
133
134             /* adc yyy */
135             X = NewCodeEntry (OP65_ADC, L[4]->AM, L[4]->Arg, 0, L[4]->LI);
136             CS_InsertEntry (S, X, IP++);
137
138             /* sta ptr1+1 */
139             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1+1", 0, L[5]->LI);
140             CS_InsertEntry (S, X, IP++);
141
142             /* ldy xxx */
143             X = NewCodeEntry (OP65_LDY, L[1]->AM, L[1]->Arg, 0, L[1]->LI);
144             CS_InsertEntry (S, X, IP++);
145
146             /* ldx #$00 */
147             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[8]->LI);
148             CS_InsertEntry (S, X, IP++);
149
150             /* lda (ptr1),y */
151             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[8]->LI);
152             CS_InsertEntry (S, X, IP++);
153
154             /* Remove the old instructions */
155             CS_DelEntries (S, I, 9);
156
157             /* Remember, we had changes */
158             ++Changes;
159
160         }
161
162         /* Next entry */
163         ++I;
164
165     }
166
167     /* Return the number of changes made */
168     return Changes;
169 }
170
171
172
173 unsigned OptPtrLoad2 (CodeSeg* S)
174 /* Search for the sequence:
175 **
176 **      adc     xxx
177 **      pha
178 **      txa
179 **      iny
180 **      adc     yyy
181 **      tax
182 **      pla
183 **      ldy
184 **      jsr     ldauidx
185 **
186 ** and replace it by:
187 **
188 **      adc     xxx
189 **      sta     ptr1
190 **      txa
191 **      iny
192 **      adc     yyy
193 **      sta     ptr1+1
194 **      ldy
195 **      ldx     #$00
196 **      lda     (ptr1),y
197 */
198 {
199     unsigned Changes = 0;
200
201     /* Walk over the entries */
202     unsigned I = 0;
203     while (I < CS_GetEntryCount (S)) {
204
205         CodeEntry* L[9];
206
207         /* Get next entry */
208         L[0] = CS_GetEntry (S, I);
209
210         /* Check for the sequence */
211         if (L[0]->OPC == OP65_ADC               &&
212             CS_GetEntries (S, L+1, I+1, 8)      &&
213             L[1]->OPC == OP65_PHA               &&
214             L[2]->OPC == OP65_TXA               &&
215             L[3]->OPC == OP65_INY               &&
216             L[4]->OPC == OP65_ADC               &&
217             L[5]->OPC == OP65_TAX               &&
218             L[6]->OPC == OP65_PLA               &&
219             L[7]->OPC == OP65_LDY               &&
220             CE_IsCallTo (L[8], "ldauidx")       &&
221             !CS_RangeHasLabel (S, I+1, 8)) {
222
223             CodeEntry* X;
224
225             /* Store the low byte and remove the PHA instead */
226             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI);
227             CS_InsertEntry (S, X, I+1);
228
229             /* Store the high byte */
230             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1+1", 0, L[4]->LI);
231             CS_InsertEntry (S, X, I+6);
232
233             /* Load high and low byte */
234             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[6]->LI);
235             CS_InsertEntry (S, X, I+10);
236             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[6]->LI);
237             CS_InsertEntry (S, X, I+11);
238
239             /* Delete the old code */
240             CS_DelEntry (S, I+12);      /* jsr ldauidx */
241             CS_DelEntry (S, I+8);       /* pla */
242             CS_DelEntry (S, I+7);       /* tax */
243             CS_DelEntry (S, I+2);       /* pha */
244
245             /* Remember, we had changes */
246             ++Changes;
247
248         }
249
250         /* Next entry */
251         ++I;
252
253     }
254
255     /* Return the number of changes made */
256     return Changes;
257 }
258
259
260
261 unsigned OptPtrLoad3 (CodeSeg* S)
262 /* Search for the sequence:
263 **
264 **      lda     #<(label+0)
265 **      ldx     #>(label+0)
266 **      clc
267 **      adc     xxx
268 **      bcc     L
269 **      inx
270 ** L:   ldy     #$00
271 **      jsr     ldauidx
272 **
273 ** and replace it by:
274 **
275 **      ldy     xxx
276 **      ldx     #$00
277 **      lda     label,y
278 */
279 {
280     unsigned Changes = 0;
281
282     /* Walk over the entries */
283     unsigned I = 0;
284     while (I < CS_GetEntryCount (S)) {
285
286         CodeEntry* L[8];
287         unsigned Len;
288
289         /* Get next entry */
290         L[0] = CS_GetEntry (S, I);
291
292         /* Check for the sequence */
293         if (L[0]->OPC == OP65_LDA                            &&
294             L[0]->AM == AM65_IMM                             &&
295             CS_GetEntries (S, L+1, I+1, 7)                   &&
296             L[1]->OPC == OP65_LDX                            &&
297             L[1]->AM == AM65_IMM                             &&
298             L[2]->OPC == OP65_CLC                            &&
299             L[3]->OPC == OP65_ADC                            &&
300             (L[3]->AM == AM65_ABS || L[3]->AM == AM65_ZP)    &&
301             (L[4]->OPC == OP65_BCC || L[4]->OPC == OP65_JCC) &&
302             L[4]->JumpTo != 0                                &&
303             L[4]->JumpTo->Owner == L[6]                      &&
304             L[5]->OPC == OP65_INX                            &&
305             L[6]->OPC == OP65_LDY                            &&
306             CE_IsKnownImm (L[6], 0)                          &&
307             CE_IsCallTo (L[7], "ldauidx")                    &&
308             !CS_RangeHasLabel (S, I+1, 5)                    &&
309             !CE_HasLabel (L[7])                              &&
310             /* Check the label last because this is quite costly */
311             (Len = strlen (L[0]->Arg)) > 3                   &&
312             L[0]->Arg[0] == '<'                              &&
313             L[0]->Arg[1] == '('                              &&
314             strlen (L[1]->Arg) == Len                        &&
315             L[1]->Arg[0] == '>'                              &&
316             memcmp (L[0]->Arg+1, L[1]->Arg+1, Len-1) == 0) {
317
318             CodeEntry* X;
319             char* Label;
320
321             /* We will create all the new stuff behind the current one so
322             ** we keep the line references.
323             */
324             X = NewCodeEntry (OP65_LDY, L[3]->AM, L[3]->Arg, 0, L[0]->LI);
325             CS_InsertEntry (S, X, I+8);
326
327             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[0]->LI);
328             CS_InsertEntry (S, X, I+9);
329
330             Label = memcpy (xmalloc (Len-2), L[0]->Arg+2, Len-3);
331             Label[Len-3] = '\0';
332             X = NewCodeEntry (OP65_LDA, AM65_ABSY, Label, 0, L[0]->LI);
333             CS_InsertEntry (S, X, I+10);
334             xfree (Label);
335
336             /* Remove the old code */
337             CS_DelEntries (S, I, 8);
338
339             /* Remember, we had changes */
340             ++Changes;
341
342         }
343
344         /* Next entry */
345         ++I;
346
347     }
348
349     /* Return the number of changes made */
350     return Changes;
351 }
352
353
354
355 unsigned OptPtrLoad4 (CodeSeg* S)
356 /* Search for the sequence:
357 **
358 **      lda     #<(label+0)
359 **      ldx     #>(label+0)
360 **      ldy     #$xx
361 **      clc
362 **      adc     (sp),y
363 **      bcc     L
364 **      inx
365 ** L:   ldy     #$00
366 **      jsr     ldauidx
367 **
368 ** and replace it by:
369 **
370 **      ldy     #$xx
371 **      lda     (sp),y
372 **      tay
373 **      ldx     #$00
374 **      lda     label,y
375 */
376 {
377     unsigned Changes = 0;
378
379     /* Walk over the entries */
380     unsigned I = 0;
381     while (I < CS_GetEntryCount (S)) {
382
383         CodeEntry* L[9];
384         unsigned Len;
385
386         /* Get next entry */
387         L[0] = CS_GetEntry (S, I);
388
389         /* Check for the sequence */
390         if (L[0]->OPC == OP65_LDA                            &&
391             L[0]->AM == AM65_IMM                             &&
392             CS_GetEntries (S, L+1, I+1, 8)                   &&
393             L[1]->OPC == OP65_LDX                            &&
394             L[1]->AM == AM65_IMM                             &&
395             !CE_HasLabel (L[1])                              &&
396             L[2]->OPC == OP65_LDY                            &&
397             CE_IsConstImm (L[2])                             &&
398             !CE_HasLabel (L[2])                              &&
399             L[3]->OPC == OP65_CLC                            &&
400             !CE_HasLabel (L[3])                              &&
401             L[4]->OPC == OP65_ADC                            &&
402             L[4]->AM == AM65_ZP_INDY                         &&
403             !CE_HasLabel (L[4])                              &&
404             (L[5]->OPC == OP65_BCC || L[5]->OPC == OP65_JCC) &&
405             L[5]->JumpTo != 0                                &&
406             L[5]->JumpTo->Owner == L[7]                      &&
407             !CE_HasLabel (L[5])                              &&
408             L[6]->OPC == OP65_INX                            &&
409             !CE_HasLabel (L[6])                              &&
410             L[7]->OPC == OP65_LDY                            &&
411             CE_IsKnownImm (L[7], 0)                          &&
412             CE_IsCallTo (L[8], "ldauidx")                    &&
413             !CE_HasLabel (L[8])                              &&
414             /* Check the label last because this is quite costly */
415             (Len = strlen (L[0]->Arg)) > 3                   &&
416             L[0]->Arg[0] == '<'                              &&
417             L[0]->Arg[1] == '('                              &&
418             strlen (L[1]->Arg) == Len                        &&
419             L[1]->Arg[0] == '>'                              &&
420             memcmp (L[0]->Arg+1, L[1]->Arg+1, Len-1) == 0) {
421
422             CodeEntry* X;
423             char* Label;
424
425             /* Add the lda */
426             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[4]->Arg, 0, L[0]->LI);
427             CS_InsertEntry (S, X, I+3);
428
429             /* Add the tay */
430             X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, L[0]->LI);
431             CS_InsertEntry (S, X, I+4);
432
433             /* Add the ldx */
434             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[0]->LI);
435             CS_InsertEntry (S, X, I+5);
436
437             /* Add the lda */
438             Label = memcpy (xmalloc (Len-2), L[0]->Arg+2, Len-3);
439             Label[Len-3] = '\0';
440             X = NewCodeEntry (OP65_LDA, AM65_ABSY, Label, 0, L[0]->LI);
441             CS_InsertEntry (S, X, I+6);
442             xfree (Label);
443
444             /* Remove the old code */
445             CS_DelEntries (S, I, 2);
446             CS_DelEntries (S, I+5, 6);
447
448             /* Remember, we had changes */
449             ++Changes;
450
451         }
452
453         /* Next entry */
454         ++I;
455
456     }
457
458     /* Return the number of changes made */
459     return Changes;
460 }
461
462
463
464 unsigned OptPtrLoad5 (CodeSeg* S)
465 /* Search for the sequence:
466 **
467 **      jsr     pushax
468 **      ldx     #$00
469 **      lda     yyy
470 **      jsr     tosaddax
471 **      ldy     #$00
472 **      jsr     ldauidx
473 **
474 ** and replace it by:
475 **
476 **      sta     ptr1
477 **      stx     ptr1+1
478 **      ldy     yyy
479 **      ldx     #$00
480 **      lda     (ptr1),y
481 */
482 {
483     unsigned Changes = 0;
484
485     /* Walk over the entries */
486     unsigned I = 0;
487     while (I < CS_GetEntryCount (S)) {
488
489         CodeEntry* L[6];
490
491         /* Get next entry */
492         L[0] = CS_GetEntry (S, I);
493
494         /* Check for the sequence */
495         if (CE_IsCallTo (L[0], "pushax")                &&
496             CS_GetEntries (S, L+1, I+1, 5)              &&
497             L[1]->OPC == OP65_LDX                       &&
498             CE_IsKnownImm (L[1], 0)                     &&
499             L[2]->OPC == OP65_LDA                       &&
500             (L[2]->AM == AM65_ABS       ||
501              L[2]->AM == AM65_ZP        ||
502              L[2]->AM == AM65_IMM)                      &&
503             CE_IsCallTo (L[3], "tosaddax")              &&
504             L[4]->OPC == OP65_LDY                       &&
505             CE_IsKnownImm (L[4], 0)                     &&
506             CE_IsCallTo (L[5], "ldauidx")               &&
507             !CS_RangeHasLabel (S, I+1, 5)) {
508
509             CodeEntry* X;
510
511             /* sta ptr1 */
512             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI);
513             CS_InsertEntry (S, X, I+6);
514
515             /* stx ptr1+1 */
516             X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[0]->LI);
517             CS_InsertEntry (S, X, I+7);
518
519             /* ldy yyy */
520             X = NewCodeEntry (OP65_LDY, L[2]->AM, L[2]->Arg, 0, L[2]->LI);
521             CS_InsertEntry (S, X, I+8);
522
523             /* ldx #$00 */
524             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[5]->LI);
525             CS_InsertEntry (S, X, I+9);
526
527             /* lda (ptr1),y */
528             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[5]->LI);
529             CS_InsertEntry (S, X, I+10);
530
531             /* Remove the old code */
532             CS_DelEntries (S, I, 6);
533
534             /* Remember, we had changes */
535             ++Changes;
536
537         }
538
539         /* Next entry */
540         ++I;
541
542     }
543
544     /* Return the number of changes made */
545     return Changes;
546 }
547
548
549
550 unsigned OptPtrLoad6 (CodeSeg* S)
551 /* Search for the sequence:
552 **
553 **      jsr     pushax
554 **      ldy     #xxx
555 **      ldx     #$00
556 **      lda     (sp),y
557 **      jsr     tosaddax
558 **      ldy     #$00
559 **      jsr     ldauidx
560 **
561 ** and replace it by:
562 **
563 **      sta     ptr1
564 **      stx     ptr1+1
565 **      ldy     #xxx-2
566 **      lda     (sp),y
567 **      tay
568 **      ldx     #$00
569 **      lda     (ptr1),y
570 */
571 {
572     unsigned Changes = 0;
573
574     /* Walk over the entries */
575     unsigned I = 0;
576     while (I < CS_GetEntryCount (S)) {
577
578         CodeEntry* L[7];
579
580         /* Get next entry */
581         L[0] = CS_GetEntry (S, I);
582
583         /* Check for the sequence */
584         if (CE_IsCallTo (L[0], "pushax")                &&
585             CS_GetEntries (S, L+1, I+1, 6)              &&
586             L[1]->OPC == OP65_LDY                       &&
587             CE_IsConstImm (L[1])                        &&
588             L[1]->Num >= 2                              &&
589             L[2]->OPC == OP65_LDX                       &&
590             CE_IsKnownImm (L[2], 0)                     &&
591             L[3]->OPC == OP65_LDA                       &&
592             L[3]->AM == AM65_ZP_INDY                    &&
593             CE_IsCallTo (L[4], "tosaddax")              &&
594             L[5]->OPC == OP65_LDY                       &&
595             CE_IsKnownImm (L[5], 0)                     &&
596             CE_IsCallTo (L[6], "ldauidx")               &&
597             !CS_RangeHasLabel (S, I+1, 6)               &&
598             !RegYUsed (S, I+7)) {
599
600             CodeEntry*  X;
601             const char* Arg;
602
603             /* sta ptr1 */
604             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI);
605             CS_InsertEntry (S, X, I+7);
606
607             /* stx ptr1+1 */
608             X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[0]->LI);
609             CS_InsertEntry (S, X, I+8);
610
611             /* ldy #xxx-2 */
612             Arg = MakeHexArg (L[1]->Num - 2);
613             X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[1]->LI);
614             CS_InsertEntry (S, X, I+9);
615
616             /* lda (sp),y */
617             X = NewCodeEntry (OP65_LDA, L[3]->AM, L[3]->Arg, 0, L[3]->LI);
618             CS_InsertEntry (S, X, I+10);
619
620             /* tay */
621             X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, L[3]->LI);
622             CS_InsertEntry (S, X, I+11);
623
624             /* ldx #$00 */
625             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[5]->LI);
626             CS_InsertEntry (S, X, I+12);
627
628             /* lda (ptr1),y */
629             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[6]->LI);
630             CS_InsertEntry (S, X, I+13);
631
632             /* Remove the old code */
633             CS_DelEntries (S, I, 7);
634
635             /* Remember, we had changes */
636             ++Changes;
637
638         }
639
640         /* Next entry */
641         ++I;
642
643     }
644
645     /* Return the number of changes made */
646     return Changes;
647 }
648
649
650
651 unsigned OptPtrLoad7 (CodeSeg* S)
652 /* Search for the sequence:
653 **
654 **      jsr     aslax1/shlax1
655 **      clc
656 **      adc     xxx
657 **      tay
658 **      txa
659 **      adc     yyy
660 **      tax
661 **      tya
662 **      ldy     zzz
663 **      jsr     ldaxidx
664 **
665 ** and replace it by:
666 **
667 **      stx     tmp1
668 **      asl     a
669 **      rol     tmp1
670 **      clc
671 **      adc     xxx
672 **      sta     ptr1
673 **      lda     tmp1
674 **      adc     yyy
675 **      sta     ptr1+1
676 **      ldy     zzz
677 **      lda     (ptr1),y
678 **      tax
679 **      dey
680 **      lda     (ptr1),y
681 */
682 {
683     unsigned Changes = 0;
684     unsigned I;
685
686     /* Walk over the entries */
687     I = 0;
688     while (I < CS_GetEntryCount (S)) {
689
690         CodeEntry* L[10];
691
692         /* Get next entry */
693         L[0] = CS_GetEntry (S, I);
694
695         /* Check for the sequence */
696         if (L[0]->OPC == OP65_JSR                               &&
697             (strcmp (L[0]->Arg, "aslax1") == 0          ||
698              strcmp (L[0]->Arg, "shlax1") == 0)                 &&
699             CS_GetEntries (S, L+1, I+1, 9)                      &&
700             L[1]->OPC == OP65_CLC                               &&
701             L[2]->OPC == OP65_ADC                               &&
702             L[3]->OPC == OP65_TAY                               &&
703             L[4]->OPC == OP65_TXA                               &&
704             L[5]->OPC == OP65_ADC                               &&
705             L[6]->OPC == OP65_TAX                               &&
706             L[7]->OPC == OP65_TYA                               &&
707             L[8]->OPC == OP65_LDY                               &&
708             CE_IsCallTo (L[9], "ldaxidx")                       &&
709             !CS_RangeHasLabel (S, I+1, 9)) {
710
711             CodeEntry* X;
712
713             /* Track the insertion point */
714             unsigned IP = I + 10;
715
716
717             /* If X is zero on entry to aslax1, we can generate:
718             **
719             **      asl     a
720             **      bcc     L1
721             **      inx
722             ** L1:  clc
723             **
724             ** instead of the code above. "lda tmp1" needs to be changed
725             ** to "txa" in this case.
726             */
727             int ShortCode = (L[0]->RI->In.RegX == 0);
728
729             if (ShortCode) {
730
731                 CodeLabel* Lab;
732
733                 /* asl a */
734                 X = NewCodeEntry (OP65_ASL, AM65_ACC, "a", 0, L[0]->LI);
735                 CS_InsertEntry (S, X, IP++);
736
737                 /* Generate clc first, since we need the label */
738                 X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[1]->LI);
739                 CS_InsertEntry (S, X, IP);
740
741                 /* Get the label */
742                 Lab = CS_GenLabel (S, X);
743
744                 /* bcc Lab */
745                 X = NewCodeEntry (OP65_BCC, AM65_BRA, Lab->Name, Lab, L[0]->LI);
746                 CS_InsertEntry (S, X, IP++);
747
748                 /* inx */
749                 X = NewCodeEntry (OP65_INX, AM65_IMP, 0, 0, L[0]->LI);
750                 CS_InsertEntry (S, X, IP++);
751
752                 /* Skip the clc insn */
753                 ++IP;
754
755             } else {
756
757                 /* stx tmp1 */
758                 X = NewCodeEntry (OP65_STX, AM65_ZP, "tmp1", 0, L[0]->LI);
759                 CS_InsertEntry (S, X, IP++);
760
761                 /* asl a */
762                 X = NewCodeEntry (OP65_ASL, AM65_ACC, "a", 0, L[0]->LI);
763                 CS_InsertEntry (S, X, IP++);
764
765                 /* rol tmp1 */
766                 X = NewCodeEntry (OP65_ROL, AM65_ZP, "tmp1", 0, L[0]->LI);
767                 CS_InsertEntry (S, X, IP++);
768
769                 /* clc */
770                 X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[1]->LI);
771                 CS_InsertEntry (S, X, IP++);
772
773             }
774
775             /* adc xxx */
776             X = NewCodeEntry (L[2]->OPC, L[2]->AM, L[2]->Arg, 0, L[2]->LI);
777             CS_InsertEntry (S, X, IP++);
778
779             /* sta ptr1 */
780             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[9]->LI);
781             CS_InsertEntry (S, X, IP++);
782
783             if (ShortCode) {
784                 /* txa */
785                 X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, L[4]->LI);
786             } else {
787                 /* lda tmp1 */
788                 X = NewCodeEntry (OP65_LDA, AM65_ZP, "tmp1", 0, L[4]->LI);
789             }
790             CS_InsertEntry (S, X, IP++);
791
792             /* adc xxx */
793             X = NewCodeEntry (L[5]->OPC, L[5]->AM, L[5]->Arg, 0, L[5]->LI);
794             CS_InsertEntry (S, X, IP++);
795
796             /* sta ptr1+1 */
797             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1+1", 0, L[9]->LI);
798             CS_InsertEntry (S, X, IP++);
799
800             /* ldy zzz */
801             X = NewCodeEntry (L[8]->OPC, L[8]->AM, L[8]->Arg, 0, L[8]->LI);
802             CS_InsertEntry (S, X, IP++);
803
804             /* lda (ptr1),y */
805             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[9]->LI);
806             CS_InsertEntry (S, X, IP++);
807
808             /* tax */
809             X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[9]->LI);
810             CS_InsertEntry (S, X, IP++);
811
812             /* dey */
813             X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[9]->LI);
814             CS_InsertEntry (S, X, IP++);
815
816             /* lda (ptr1),y */
817             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[9]->LI);
818             CS_InsertEntry (S, X, IP++);
819
820             /* Remove the old code */
821             CS_DelEntries (S, I, 10);
822
823             /* Remember, we had changes */
824             ++Changes;
825
826         }
827
828         /* Next entry */
829         ++I;
830
831     }
832
833     /* Return the number of changes made */
834     return Changes;
835 }
836
837
838
839 unsigned OptPtrLoad11 (CodeSeg* S)
840 /* Search for the sequence:
841 **
842 **      clc
843 **      adc     xxx
844 **      bcc     L
845 **      inx
846 ** L:   ldy     #$00
847 **      jsr     ldauidx
848 **
849 ** and replace it by:
850 **
851 **      ldy     xxx
852 **      sta     ptr1
853 **      stx     ptr1+1
854 **      ldx     #$00
855 **      lda     (ptr1),y
856 */
857 {
858     unsigned Changes = 0;
859
860     /* Walk over the entries */
861     unsigned I = 0;
862     while (I < CS_GetEntryCount (S)) {
863
864         CodeEntry* L[6];
865
866         /* Get next entry */
867         L[0] = CS_GetEntry (S, I);
868
869         /* Check for the sequence */
870         if (L[0]->OPC == OP65_CLC                            &&
871             CS_GetEntries (S, L+1, I+1, 5)                   &&
872             L[1]->OPC == OP65_ADC                            &&
873             (L[1]->AM == AM65_ABS || L[1]->AM == AM65_ZP || L[1]->AM == AM65_IMM)    &&
874             (L[2]->OPC == OP65_BCC || L[2]->OPC == OP65_JCC) &&
875             L[2]->JumpTo != 0                                &&
876             L[2]->JumpTo->Owner == L[4]                      &&
877             L[3]->OPC == OP65_INX                            &&
878             L[4]->OPC == OP65_LDY                            &&
879             CE_IsKnownImm (L[4], 0)                          &&
880             CE_IsCallTo (L[5], "ldauidx")                    &&
881             !CS_RangeHasLabel (S, I+1, 3)                    &&
882             !CE_HasLabel (L[5])) {
883
884             CodeEntry* X;
885
886             /* We will create all the new stuff behind the current one so
887             ** we keep the line references.
888             */
889             X = NewCodeEntry (OP65_LDY, L[1]->AM, L[1]->Arg, 0, L[0]->LI);
890             CS_InsertEntry (S, X, I+6);
891
892             /* sta ptr1 */
893             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI);
894             CS_InsertEntry (S, X, I+7);
895
896             /* stx ptr1+1 */
897             X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[0]->LI);
898             CS_InsertEntry (S, X, I+8);
899
900             /* ldx #$00 */
901             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[0]->LI);
902             CS_InsertEntry (S, X, I+9);
903
904             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[0]->LI);
905             CS_InsertEntry (S, X, I+10);
906
907             /* Remove the old code */
908             CS_DelEntries (S, I, 6);
909
910             /* Remember, we had changes */
911             ++Changes;
912
913         }
914
915         /* Next entry */
916         ++I;
917
918     }
919
920     /* Return the number of changes made */
921     return Changes;
922 }
923
924
925
926 unsigned OptPtrLoad12 (CodeSeg* S)
927 /* Search for the sequence:
928 **
929 **      lda     regbank+n
930 **      ldx     regbank+n+1
931 **      sta     regsave
932 **      stx     regsave+1
933 **      clc
934 **      adc     #$01
935 **      bcc     L0005
936 **      inx
937 ** L:   sta     regbank+n
938 **      stx     regbank+n+1
939 **      lda     regsave
940 **      ldx     regsave+1
941 **      ldy     #$00
942 **      jsr     ldauidx
943 **
944 ** and replace it by:
945 **
946 **      ldy     #$00
947 **      ldx     #$00
948 **      lda     (regbank+n),y
949 **      inc     regbank+n
950 **      bne     L1
951 **      inc     regbank+n+1
952 ** L1:  tay                     <- only if flags are used
953 **
954 ** This function must execute before OptPtrLoad7!
955 **
956 */
957 {
958     unsigned Changes = 0;
959
960     /* Walk over the entries */
961     unsigned I = 0;
962     while (I < CS_GetEntryCount (S)) {
963
964         CodeEntry* L[15];
965         unsigned Len;
966
967         /* Get next entry */
968         L[0] = CS_GetEntry (S, I);
969
970         /* Check for the sequence */
971         if (L[0]->OPC == OP65_LDA                               &&
972             L[0]->AM == AM65_ZP                                 &&
973             strncmp (L[0]->Arg, "regbank+", 8) == 0             &&
974             (Len = strlen (L[0]->Arg)) > 0                      &&
975             CS_GetEntries (S, L+1, I+1, 14)                     &&
976             !CS_RangeHasLabel (S, I+1, 7)                       &&
977             !CS_RangeHasLabel (S, I+9, 5)                       &&
978             L[1]->OPC == OP65_LDX                               &&
979             L[1]->AM == AM65_ZP                                 &&
980             strncmp (L[1]->Arg, L[0]->Arg, Len) == 0            &&
981             strcmp (L[1]->Arg+Len, "+1") == 0                   &&
982             L[2]->OPC == OP65_STA                               &&
983             L[2]->AM == AM65_ZP                                 &&
984             strcmp (L[2]->Arg, "regsave") == 0                  &&
985             L[3]->OPC == OP65_STX                               &&
986             L[3]->AM == AM65_ZP                                 &&
987             strcmp (L[3]->Arg, "regsave+1") == 0                &&
988             L[4]->OPC == OP65_CLC                               &&
989             L[5]->OPC == OP65_ADC                               &&
990             CE_IsKnownImm (L[5], 1)                             &&
991             L[6]->OPC == OP65_BCC                               &&
992             L[6]->JumpTo != 0                                   &&
993             L[6]->JumpTo->Owner == L[8]                         &&
994             L[7]->OPC == OP65_INX                               &&
995             L[8]->OPC == OP65_STA                               &&
996             L[8]->AM == AM65_ZP                                 &&
997             strcmp (L[8]->Arg, L[0]->Arg) == 0                  &&
998             L[9]->OPC == OP65_STX                               &&
999             L[9]->AM == AM65_ZP                                 &&
1000             strcmp (L[9]->Arg, L[1]->Arg) == 0                  &&
1001             L[10]->OPC == OP65_LDA                              &&
1002             L[10]->AM == AM65_ZP                                &&
1003             strcmp (L[10]->Arg, "regsave") == 0                 &&
1004             L[11]->OPC == OP65_LDX                              &&
1005             L[11]->AM == AM65_ZP                                &&
1006             strcmp (L[11]->Arg, "regsave+1") == 0               &&
1007             L[12]->OPC == OP65_LDY                              &&
1008             CE_IsConstImm (L[12])                               &&
1009             CE_IsCallTo (L[13], "ldauidx")) {
1010
1011             CodeEntry* X;
1012             CodeLabel* Label;
1013
1014             /* Check if the instruction following the sequence uses the flags
1015             ** set by the load. If so, insert a test of the value in the
1016             ** accumulator.
1017             */
1018             if (CE_UseLoadFlags (L[14])) {
1019                 X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, L[13]->LI);
1020                 CS_InsertEntry (S, X, I+14);
1021             }
1022
1023             /* Attach a label to L[14]. This may be either the just inserted
1024             ** instruction, or the one following the sequence.
1025             */
1026             Label = CS_GenLabel (S, L[14]);
1027
1028             /* ldy #$xx */
1029             X = NewCodeEntry (OP65_LDY, AM65_IMM, L[12]->Arg, 0, L[12]->LI);
1030             CS_InsertEntry (S, X, I+14);
1031
1032             /* ldx #$xx */
1033             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[13]->LI);
1034             CS_InsertEntry (S, X, I+15);
1035
1036             /* lda (regbank+n),y */
1037             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[13]->LI);
1038             CS_InsertEntry (S, X, I+16);
1039
1040             /* inc regbank+n */
1041             X = NewCodeEntry (OP65_INC, AM65_ZP, L[0]->Arg, 0, L[5]->LI);
1042             CS_InsertEntry (S, X, I+17);
1043
1044             /* bne ... */
1045             X = NewCodeEntry (OP65_BNE, AM65_BRA, Label->Name, Label, L[6]->LI);
1046             CS_InsertEntry (S, X, I+18);
1047
1048             /* inc regbank+n+1 */
1049             X = NewCodeEntry (OP65_INC, AM65_ZP, L[1]->Arg, 0, L[7]->LI);
1050             CS_InsertEntry (S, X, I+19);
1051
1052             /* Delete the old code */
1053             CS_DelEntries (S, I, 14);
1054
1055             /* Remember, we had changes */
1056             ++Changes;
1057
1058         }
1059
1060         /* Next entry */
1061         ++I;
1062
1063     }
1064
1065     /* Return the number of changes made */
1066     return Changes;
1067 }
1068
1069
1070
1071 unsigned OptPtrLoad13 (CodeSeg* S)
1072 /* Search for the sequence:
1073 **
1074 **      lda     zp
1075 **      ldx     zp+1
1076 **      ldy     xx
1077 **      jsr     ldauidx
1078 **
1079 ** and replace it by:
1080 **
1081 **      ldy     xx
1082 **      ldx     #$00
1083 **      lda     (zp),y
1084 */
1085 {
1086     unsigned Changes = 0;
1087
1088     /* Walk over the entries */
1089     unsigned I = 0;
1090     while (I < CS_GetEntryCount (S)) {
1091
1092         CodeEntry* L[4];
1093         unsigned Len;
1094
1095         /* Get next entry */
1096         L[0] = CS_GetEntry (S, I);
1097
1098         /* Check for the sequence */
1099         if (L[0]->OPC == OP65_LDA && L[0]->AM == AM65_ZP        &&
1100             CS_GetEntries (S, L+1, I+1, 3)                      &&
1101             !CS_RangeHasLabel (S, I+1, 3)                       &&
1102             L[1]->OPC == OP65_LDX && L[1]->AM == AM65_ZP        &&
1103             (Len = strlen (L[0]->Arg)) > 0                      &&
1104             strncmp (L[0]->Arg, L[1]->Arg, Len) == 0            &&
1105             strcmp (L[1]->Arg + Len, "+1") == 0                 &&
1106             L[2]->OPC == OP65_LDY                               &&
1107             CE_IsCallTo (L[3], "ldauidx")) {
1108
1109             CodeEntry* X;
1110
1111             /* ldx #$00 */
1112             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[3]->LI);
1113             CS_InsertEntry (S, X, I+3);
1114
1115             /* lda (zp),y */
1116             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI);
1117             CS_InsertEntry (S, X, I+4);
1118
1119             /* Remove the old code */
1120             CS_DelEntry (S, I+5);
1121             CS_DelEntries (S, I, 2);
1122
1123             /* Remember, we had changes */
1124             ++Changes;
1125
1126         }
1127
1128         /* Next entry */
1129         ++I;
1130
1131     }
1132
1133     /* Return the number of changes made */
1134     return Changes;
1135 }
1136
1137
1138
1139 unsigned OptPtrLoad14 (CodeSeg* S)
1140 /* Search for the sequence:
1141 **
1142 **      lda     zp
1143 **      ldx     zp+1
1144 **      (anything that doesn't change a/x)
1145 **      ldy     xx
1146 **      jsr     ldauidx
1147 **
1148 ** and replace it by:
1149 **
1150 **      lda     zp
1151 **      ldx     zp+1
1152 **      (anything that doesn't change a/x)
1153 **      ldy     xx
1154 **      ldx     #$00
1155 **      lda     (zp),y
1156 */
1157 {
1158     unsigned Changes = 0;
1159     unsigned I;
1160
1161     /* Walk over the entries */
1162     I = 0;
1163     while (I < CS_GetEntryCount (S)) {
1164
1165         CodeEntry* L[5];
1166         unsigned Len;
1167
1168         /* Get next entry */
1169         L[0] = CS_GetEntry (S, I);
1170
1171         /* Check for the sequence */
1172         if (L[0]->OPC == OP65_LDA && L[0]->AM == AM65_ZP        &&
1173             CS_GetEntries (S, L+1, I+1, 4)                      &&
1174             !CS_RangeHasLabel (S, I+1, 4)                       &&
1175             L[1]->OPC == OP65_LDX && L[1]->AM == AM65_ZP        &&
1176             (Len = strlen (L[0]->Arg)) > 0                      &&
1177             strncmp (L[0]->Arg, L[1]->Arg, Len) == 0            &&
1178             strcmp (L[1]->Arg + Len, "+1") == 0                 &&
1179             (L[2]->Chg & REG_AX) == 0                           &&
1180             L[3]->OPC == OP65_LDY                               &&
1181             CE_IsCallTo (L[4], "ldauidx")) {
1182
1183             CodeEntry* X;
1184
1185             /* ldx #$00 */
1186             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[3]->LI);
1187             CS_InsertEntry (S, X, I+5);
1188
1189             /* lda (zp),y */
1190             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI);
1191             CS_InsertEntry (S, X, I+6);
1192
1193             /* Remove the old code */
1194             CS_DelEntry (S, I+4);
1195
1196             /* Remember, we had changes */
1197             ++Changes;
1198
1199         }
1200
1201         /* Next entry */
1202         ++I;
1203
1204     }
1205
1206     /* Return the number of changes made */
1207     return Changes;
1208 }
1209
1210
1211
1212 unsigned OptPtrLoad15 (CodeSeg* S)
1213 /* Search for the sequence:
1214 **
1215 **      lda     zp
1216 **      ldx     zp+1
1217 **      jsr     pushax          <- optional
1218 **      ldy     xx
1219 **      jsr     ldaxidx
1220 **
1221 ** and replace it by:
1222 **
1223 **      lda     zp              <- only if
1224 **      ldx     zp+1            <- call to
1225 **      jsr     pushax          <- pushax present
1226 **      ldy     xx
1227 **      lda     (zp),y
1228 **      tax
1229 **      dey
1230 **      lda     (zp),y
1231 */
1232 {
1233     unsigned Changes = 0;
1234
1235     /* Walk over the entries */
1236     unsigned I = 0;
1237     while (I < CS_GetEntryCount (S)) {
1238
1239         CodeEntry* L[5];
1240         unsigned Len;
1241
1242         /* Check for the start of the sequence */
1243         if (CS_GetEntries (S, L, I, 3)                          &&
1244             L[0]->OPC == OP65_LDA && L[0]->AM == AM65_ZP        &&
1245             L[1]->OPC == OP65_LDX && L[1]->AM == AM65_ZP        &&
1246             !CS_RangeHasLabel (S, I+1, 2)                       &&
1247             (Len = strlen (L[0]->Arg)) > 0                      &&
1248             strncmp (L[0]->Arg, L[1]->Arg, Len) == 0            &&
1249             strcmp (L[1]->Arg + Len, "+1") == 0) {
1250
1251             unsigned PushAX = CE_IsCallTo (L[2], "pushax");
1252
1253             /* Check for the remainder of the sequence */
1254             if (CS_GetEntries (S, L+3, I+3, 1 + PushAX)         &&
1255                 !CS_RangeHasLabel (S, I+3, 1 + PushAX)          &&
1256                 L[2+PushAX]->OPC == OP65_LDY                    &&
1257                 CE_IsCallTo (L[3+PushAX], "ldaxidx")) {
1258
1259                 CodeEntry* X;
1260
1261                 /* lda (zp),y */
1262                 X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI);
1263                 CS_InsertEntry (S, X, I+PushAX+4);
1264
1265                 /* tax */
1266                 X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[3]->LI);
1267                 CS_InsertEntry (S, X, I+PushAX+5);
1268
1269                 /* dey */
1270                 X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[3]->LI);
1271                 CS_InsertEntry (S, X, I+PushAX+6);
1272
1273                 /* lda (zp),y */
1274                 X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI);
1275                 CS_InsertEntry (S, X, I+PushAX+7);
1276
1277                 /* Remove the old code */
1278                 CS_DelEntry (S, I+PushAX+3);
1279                 if (!PushAX) {
1280                     CS_DelEntries (S, I, 2);
1281                 }
1282
1283                 /* Remember, we had changes */
1284                 ++Changes;
1285
1286             }
1287         }
1288
1289         /* Next entry */
1290         ++I;
1291
1292     }
1293
1294     /* Return the number of changes made */
1295     return Changes;
1296 }
1297
1298
1299
1300 unsigned OptPtrLoad16 (CodeSeg* S)
1301 /* Search for the sequence
1302 **
1303 **      ldy     ...
1304 **      jsr     ldauidx
1305 **
1306 ** and replace it by:
1307 **
1308 **      stx     ptr1+1
1309 **      sta     ptr1
1310 **      ldy     ...
1311 **      ldx     #$00
1312 **      lda     (ptr1),y
1313 **
1314 ** This step must be executed *after* OptPtrLoad1!
1315 */
1316 {
1317     unsigned Changes = 0;
1318
1319     /* Walk over the entries */
1320     unsigned I = 0;
1321     while (I < CS_GetEntryCount (S)) {
1322
1323         CodeEntry* L[2];
1324
1325         /* Get next entry */
1326         L[0] = CS_GetEntry (S, I);
1327
1328         /* Check for the sequence */
1329         if (L[0]->OPC == OP65_LDY               &&
1330             CS_GetEntries (S, L+1, I+1, 1)      &&
1331             CE_IsCallTo (L[1], "ldauidx")       &&
1332             !CE_HasLabel (L[1])) {
1333
1334             CodeEntry* X;
1335
1336             /* stx ptr1+1 */
1337             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[1]->LI);
1338             CS_InsertEntry (S, X, I+2);
1339
1340             /* sta ptr1 */
1341             X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[1]->LI);
1342             CS_InsertEntry (S, X, I+3);
1343
1344             /* ldy ... */
1345             X = NewCodeEntry (L[0]->OPC, L[0]->AM, L[0]->Arg, 0, L[0]->LI);
1346             CS_InsertEntry (S, X, I+4);
1347
1348             /* ldx #$00 */
1349             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[1]->LI);
1350             CS_InsertEntry (S, X, I+5);
1351
1352             /* lda (ptr1),y */
1353             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[1]->LI);
1354             CS_InsertEntry (S, X, I+6);
1355
1356             /* Delete the old code */
1357             CS_DelEntries (S, I, 2);
1358
1359             /* Remember, we had changes */
1360             ++Changes;
1361
1362         }
1363
1364         /* Next entry */
1365         ++I;
1366
1367     }
1368
1369     /* Return the number of changes made */
1370     return Changes;
1371 }
1372
1373
1374
1375 unsigned OptPtrLoad17 (CodeSeg* S)
1376 /* Search for the sequence
1377 **
1378 **      ldy     ...
1379 **      jsr     ldaxidx
1380 **
1381 ** and replace it by:
1382 **
1383 **      sta     ptr1
1384 **      stx     ptr1+1
1385 **      ldy     ...
1386 **      lda     (ptr1),y
1387 **      tax
1388 **      dey
1389 **      lda     (ptr1),y
1390 **
1391 ** This step must be executed *after* OptPtrLoad9! While code size increases
1392 ** by more than 200%, inlining will greatly improve visibility for the
1393 ** optimizer, so often part of the code gets improved later. So we will mark
1394 ** the step with less than 200% so it gets executed when -Oi is in effect.
1395 */
1396 {
1397     unsigned Changes = 0;
1398
1399     /* Walk over the entries */
1400     unsigned I = 0;
1401     while (I < CS_GetEntryCount (S)) {
1402
1403         CodeEntry* L[2];
1404
1405         /* Get next entry */
1406         L[0] = CS_GetEntry (S, I);
1407
1408         /* Check for the sequence */
1409         if (L[0]->OPC == OP65_LDY               &&
1410             CS_GetEntries (S, L+1, I+1, 1)      &&
1411             CE_IsCallTo (L[1], "ldaxidx")       &&
1412             !CE_HasLabel (L[1])) {
1413
1414             CodeEntry* X;
1415
1416             /* Store the high byte */
1417             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI);
1418             CS_InsertEntry (S, X, I+2);
1419
1420             /* Store the low byte */
1421             X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[0]->LI);
1422             CS_InsertEntry (S, X, I+3);
1423
1424             /* ldy ... */
1425             X = NewCodeEntry (L[0]->OPC, L[0]->AM, L[0]->Arg, 0, L[0]->LI);
1426             CS_InsertEntry (S, X, I+4);
1427
1428             /* lda (ptr1),y */
1429             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[1]->LI);
1430             CS_InsertEntry (S, X, I+5);
1431
1432             /* tax */
1433             X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[1]->LI);
1434             CS_InsertEntry (S, X, I+6);
1435
1436             /* dey */
1437             X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[1]->LI);
1438             CS_InsertEntry (S, X, I+7);
1439
1440             /* lda (ptr1),y */
1441             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[1]->LI);
1442             CS_InsertEntry (S, X, I+8);
1443
1444             /* Delete original sequence */
1445             CS_DelEntries (S, I, 2);
1446
1447             /* Remember, we had changes */
1448             ++Changes;
1449
1450         }
1451
1452         /* Next entry */
1453         ++I;
1454
1455     }
1456
1457     /* Return the number of changes made */
1458     return Changes;
1459 }
1460
1461
1462
1463 unsigned OptPtrLoad18 (CodeSeg* S)
1464 /* Search for the sequence:
1465 **
1466 **      ldx     #$xx
1467 **      lda     #$yy
1468 **      clc
1469 **      adc     xxx
1470 **      bcc     L
1471 **      inx
1472 ** L:   ldy     #$00
1473 **      jsr     ldauidx
1474 **
1475 ** and replace it by:
1476 **
1477 **      ldy     xxx
1478 **      ldx     #$00
1479 **      lda     $xxyy,y
1480 **
1481 ** This is similar to OptPtrLoad3 but works on a constant address
1482 ** instead of a label. Also, the initial X and A loads are reversed.
1483 ** Must be run before OptPtrLoad11.
1484 */
1485 {
1486     unsigned Changes = 0;
1487
1488     /* Walk over the entries */
1489     unsigned I = 0;
1490     while (I < CS_GetEntryCount (S)) {
1491
1492         CodeEntry* L[8];
1493
1494         /* Get next entry */
1495         L[0] = CS_GetEntry (S, I);
1496
1497         /* Check for the sequence */
1498         if (L[0]->OPC == OP65_LDX                            &&
1499             L[0]->AM == AM65_IMM                             &&
1500             CS_GetEntries (S, L+1, I+1, 7)                   &&
1501             L[1]->OPC == OP65_LDA                            &&
1502             L[1]->AM == AM65_IMM                             &&
1503             L[2]->OPC == OP65_CLC                            &&
1504             L[3]->OPC == OP65_ADC                            &&
1505             (L[3]->AM == AM65_ABS || L[3]->AM == AM65_ZP)    &&
1506             (L[4]->OPC == OP65_BCC || L[4]->OPC == OP65_JCC) &&
1507             L[4]->JumpTo != 0                                &&
1508             L[4]->JumpTo->Owner == L[6]                      &&
1509             L[5]->OPC == OP65_INX                            &&
1510             L[6]->OPC == OP65_LDY                            &&
1511             CE_IsKnownImm (L[6], 0)                          &&
1512             CE_IsCallTo (L[7], "ldauidx")                    &&
1513             !CS_RangeHasLabel (S, I+1, 5)                    &&
1514             !CE_HasLabel (L[7])                              &&
1515             strlen (L[0]->Arg) == 3                          &&
1516             L[0]->Arg[0] == '$'                              &&
1517             strlen (L[1]->Arg) == 3                          &&
1518             L[1]->Arg[0] == '$'                              ) {
1519
1520             CodeEntry* X;
1521             char* Label;
1522
1523             /* We will create all the new stuff behind the current one so
1524             ** we keep the line references.
1525             */
1526             X = NewCodeEntry (OP65_LDY, L[3]->AM, L[3]->Arg, 0, L[0]->LI);
1527             CS_InsertEntry (S, X, I+8);
1528
1529             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[0]->LI);
1530             CS_InsertEntry (S, X, I+9);
1531
1532             Label = xmalloc(6);
1533             sprintf(Label, "$%s%s", L[0]->Arg+1, L[1]->Arg+1);
1534             X = NewCodeEntry (OP65_LDA, AM65_ABSY, Label, 0, L[0]->LI);
1535             CS_InsertEntry (S, X, I+10);
1536             xfree (Label);
1537
1538             /* Remove the old code */
1539             CS_DelEntries (S, I, 8);
1540
1541             /* Remember, we had changes */
1542             ++Changes;
1543
1544         }
1545
1546         /* Next entry */
1547         ++I;
1548
1549     }
1550
1551     /* Return the number of changes made */
1552     return Changes;
1553 }
1554
1555
1556
1557 unsigned OptPtrLoad19 (CodeSeg* S)
1558 /* Search for the sequence:
1559 **
1560 **      ldx     #0
1561 **      and     #mask           (any value < 128)
1562 **      jsr     aslax1/shlax1
1563 **      clc
1564 **      adc     #<(label+0)
1565 **      tay
1566 **      txa
1567 **      adc     #>(label+0)
1568 **      tax
1569 **      tya
1570 **      ldy     #$01
1571 **      jsr     ldaxidx
1572 **
1573 ** and replace it by:
1574 **
1575 **      ldx     #0
1576 **      and     #mask           (remove if == 127)
1577 **      asl
1578 **      tay
1579 **      lda     label,y
1580 **      ldx     label+1,y
1581 */
1582 {
1583     unsigned Changes = 0;
1584     unsigned I;
1585
1586     /* Walk over the entries */
1587     I = 0;
1588     while (I < CS_GetEntryCount (S)) {
1589
1590         CodeEntry* L[12];
1591
1592         /* Get next entry */
1593         L[0] = CS_GetEntry (S, I);
1594
1595         /* Check for the sequence */
1596         if (L[0]->OPC == OP65_LDX                               &&
1597             CE_IsKnownImm(L[0], 0)                              &&
1598             CS_GetEntries (S, L+1, I+1, 11)                     &&
1599             L[1]->OPC == OP65_AND                               &&
1600             L[1]->AM == AM65_IMM                                &&
1601             CE_HasNumArg (L[1]) && L[1]->Num <= 127             &&
1602             L[2]->OPC == OP65_JSR                               &&
1603             (strcmp (L[2]->Arg, "aslax1") == 0          ||
1604              strcmp (L[2]->Arg, "shlax1") == 0)                 &&
1605             L[3]->OPC == OP65_CLC                               &&
1606             L[4]->OPC == OP65_ADC                               &&
1607             L[5]->OPC == OP65_TAY                               &&
1608             L[6]->OPC == OP65_TXA                               &&
1609             L[7]->OPC == OP65_ADC                               &&
1610             L[8]->OPC == OP65_TAX                               &&
1611             L[9]->OPC == OP65_TYA                               &&
1612             L[10]->OPC == OP65_LDY                               &&
1613             CE_IsKnownImm(L[10], 1)                              &&
1614             strlen(L[4]->Arg) >= 3                              &&
1615             L[4]->Arg[0] == '<'                                 &&
1616             strlen(L[7]->Arg) >= 3                              &&
1617             L[7]->Arg[0] == '>'                                 &&
1618             !strcmp(L[4]->Arg+1, L[7]->Arg+1)                   &&
1619             CE_IsCallTo (L[11], "ldaxidx")                      &&
1620             !CS_RangeHasLabel (S, I+1, 11)) {
1621
1622             CodeEntry* X;
1623             char* Label;
1624             int Len = strlen(L[4]->Arg);
1625
1626             /* Track the insertion point */
1627             unsigned IP = I + 12;
1628
1629             /* asl a */
1630             X = NewCodeEntry (OP65_ASL, AM65_ACC, "a", 0, L[2]->LI);
1631             CS_InsertEntry (S, X, IP++);
1632
1633             /* tay */
1634             X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, L[2]->LI);
1635             CS_InsertEntry (S, X, IP++);
1636
1637             /* lda label,y */
1638             Label = memcpy (xmalloc (Len-2), L[4]->Arg+2, Len-3);
1639             Label[Len-3] = '\0';
1640             X = NewCodeEntry (OP65_LDA, AM65_ABSY, Label, 0, L[10]->LI);
1641             CS_InsertEntry (S, X, IP++);
1642             xfree (Label);
1643
1644             /* lda label+1,y */
1645             Label = memcpy (xmalloc (Len), L[4]->Arg+2, Len-3);
1646             strcpy(&Label[Len-3], "+1");
1647             X = NewCodeEntry (OP65_LDX, AM65_ABSY, Label, 0, L[10]->LI);
1648             CS_InsertEntry (S, X, IP++);
1649             xfree (Label);
1650
1651             /* Remove the old code */
1652             /* Remove the AND only if it's == 127, since ASL erases high bit */
1653             if (L[1]->Num == 127)
1654                 CS_DelEntries (S, I+1, 11);
1655             else
1656                 CS_DelEntries (S, I+2, 10);
1657             /* Remove the ldx #0 */
1658             CS_DelEntry(S, I);
1659
1660             /* Remember, we had changes */
1661             ++Changes;
1662
1663         }
1664
1665         /* Next entry */
1666         ++I;
1667
1668     }
1669
1670     /* Return the number of changes made */
1671     return Changes;
1672 }
1673
1674
1675