]> git.sur5r.net Git - cc65/blob - src/cc65/coptptrload.c
Improvements in array index code.
[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;
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 is now in the right place */
131             ++IP;
132
133             /* adc yyy */
134             X = NewCodeEntry (OP65_ADC, L[4]->AM, L[4]->Arg, 0, L[4]->LI);
135             CS_InsertEntry (S, X, IP++);
136
137             /* sta ptr1+1 */
138             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1+1", 0, L[5]->LI);
139             CS_InsertEntry (S, X, IP++);
140
141             /* ldy xxx */
142             X = NewCodeEntry (OP65_LDY, L[1]->AM, L[1]->Arg, 0, L[1]->LI);
143             CS_InsertEntry (S, X, IP++);
144
145             /* ldx #$00 */
146             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[8]->LI);
147             CS_InsertEntry (S, X, IP++);
148
149             /* lda (ptr1),y */
150             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[8]->LI);
151             CS_InsertEntry (S, X, IP++);
152
153             /* Remove the old instructions */
154             CS_DelEntries (S, IP, 8);
155
156             /* Remember, we had changes */
157             ++Changes;
158
159         }
160
161         /* Next entry */
162         ++I;
163
164     }
165
166     /* Return the number of changes made */
167     return Changes;
168 }
169
170
171
172 unsigned OptPtrLoad2 (CodeSeg* S)
173 /* Search for the sequence:
174  *
175  *      adc     xxx
176  *      pha
177  *      txa
178  *      iny
179  *      adc     yyy
180  *      tax
181  *      pla
182  *      ldy
183  *      jsr     ldauidx
184  *
185  * and replace it by:
186  *
187  *      adc     xxx
188  *      sta     ptr1
189  *      txa
190  *      iny
191  *      adc     yyy
192  *      sta     ptr1+1
193  *      ldy
194  *      ldx     #$00
195  *      lda     (ptr1),y
196  */
197 {
198     unsigned Changes = 0;
199
200     /* Walk over the entries */
201     unsigned I = 0;
202     while (I < CS_GetEntryCount (S)) {
203
204         CodeEntry* L[9];
205
206         /* Get next entry */
207         L[0] = CS_GetEntry (S, I);
208
209         /* Check for the sequence */
210         if (L[0]->OPC == OP65_ADC               &&
211             CS_GetEntries (S, L+1, I+1, 8)      &&
212             L[1]->OPC == OP65_PHA               &&
213             L[2]->OPC == OP65_TXA               &&
214             L[3]->OPC == OP65_INY               &&
215             L[4]->OPC == OP65_ADC               &&
216             L[5]->OPC == OP65_TAX               &&
217             L[6]->OPC == OP65_PLA               &&
218             L[7]->OPC == OP65_LDY               &&
219             CE_IsCallTo (L[8], "ldauidx")       &&
220             !CS_RangeHasLabel (S, I+1, 8)) {
221
222             CodeEntry* X;
223
224             /* Store the low byte and remove the PHA instead */
225             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI);
226             CS_InsertEntry (S, X, I+1);
227
228             /* Store the high byte */
229             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1+1", 0, L[4]->LI);
230             CS_InsertEntry (S, X, I+6);
231
232             /* Load high and low byte */
233             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[6]->LI);
234             CS_InsertEntry (S, X, I+10);
235             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[6]->LI);
236             CS_InsertEntry (S, X, I+11);
237
238             /* Delete the old code */
239             CS_DelEntry (S, I+12);      /* jsr ldauidx */
240             CS_DelEntry (S, I+8);       /* pla */
241             CS_DelEntry (S, I+7);       /* tax */
242             CS_DelEntry (S, I+2);       /* pha */
243
244             /* Remember, we had changes */
245             ++Changes;
246
247         }
248
249         /* Next entry */
250         ++I;
251
252     }
253
254     /* Return the number of changes made */
255     return Changes;
256 }
257
258
259
260 unsigned OptPtrLoad3 (CodeSeg* S)
261 /* Search for the sequence:
262  *
263  *      lda     #<(label+0)
264  *      ldx     #>(label+0)
265  *      clc
266  *      adc     xxx
267  *      bcc     L
268  *      inx
269  * L:   ldy     #$00
270  *      jsr     ldauidx
271  *
272  * and replace it by:
273  *
274  *      ldy     xxx
275  *      ldx     #$00
276  *      lda     label,y
277  */
278 {
279     unsigned Changes = 0;
280
281     /* Walk over the entries */
282     unsigned I = 0;
283     while (I < CS_GetEntryCount (S)) {
284
285         CodeEntry* L[8];
286         unsigned Len;
287
288         /* Get next entry */
289         L[0] = CS_GetEntry (S, I);
290
291         /* Check for the sequence */
292         if (L[0]->OPC == OP65_LDA                            &&
293             L[0]->AM == AM65_IMM                             &&
294             CS_GetEntries (S, L+1, I+1, 7)                   &&
295             L[1]->OPC == OP65_LDX                            &&
296             L[1]->AM == AM65_IMM                             &&
297             L[2]->OPC == OP65_CLC                            &&
298             L[3]->OPC == OP65_ADC                            &&
299             (L[3]->AM == AM65_ABS || L[3]->AM == AM65_ZP)    &&
300             (L[4]->OPC == OP65_BCC || L[4]->OPC == OP65_JCC) &&
301             L[4]->JumpTo != 0                                &&
302             L[4]->JumpTo->Owner == L[6]                      &&
303             L[5]->OPC == OP65_INX                            &&
304             L[6]->OPC == OP65_LDY                            &&
305             CE_IsKnownImm (L[6], 0)                          &&
306             CE_IsCallTo (L[7], "ldauidx")                    &&
307             !CS_RangeHasLabel (S, I+1, 5)                    &&
308             !CE_HasLabel (L[7])                              &&
309             /* Check the label last because this is quite costly */
310             (Len = strlen (L[0]->Arg)) > 3                   &&
311             L[0]->Arg[0] == '<'                              &&
312             L[0]->Arg[1] == '('                              &&
313             strlen (L[1]->Arg) == Len                        &&
314             L[1]->Arg[0] == '>'                              &&
315             memcmp (L[0]->Arg+1, L[1]->Arg+1, Len-1) == 0) {
316
317             CodeEntry* X;
318             char* Label;
319
320             /* We will create all the new stuff behind the current one so
321              * we keep the line references.
322              */
323             X = NewCodeEntry (OP65_LDY, L[3]->AM, L[3]->Arg, 0, L[0]->LI);
324             CS_InsertEntry (S, X, I+8);
325
326             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[0]->LI);
327             CS_InsertEntry (S, X, I+9);
328
329             Label = memcpy (xmalloc (Len-2), L[0]->Arg+2, Len-3);
330             Label[Len-3] = '\0';
331             X = NewCodeEntry (OP65_LDA, AM65_ABSY, Label, 0, L[0]->LI);
332             CS_InsertEntry (S, X, I+10);
333             xfree (Label);
334
335             /* Remove the old code */
336             CS_DelEntries (S, I, 8);
337
338             /* Remember, we had changes */
339             ++Changes;
340
341         }
342
343         /* Next entry */
344         ++I;
345
346     }
347
348     /* Return the number of changes made */
349     return Changes;
350 }
351
352
353
354 unsigned OptPtrLoad4 (CodeSeg* S)
355 /* Search for the sequence:
356  *
357  *      lda     #<(label+0)
358  *      ldx     #>(label+0)
359  *      ldy     #$xx
360  *      clc
361  *      adc     (sp),y
362  *      bcc     L
363  *      inx
364  * L:   ldy     #$00
365  *      jsr     ldauidx
366  *
367  * and replace it by:
368  *
369  *      ldy     #$xx
370  *      lda     (sp),y
371  *      tay
372  *      ldx     #$00
373  *      lda     label,y
374  */
375 {
376     unsigned Changes = 0;
377
378     /* Walk over the entries */
379     unsigned I = 0;
380     while (I < CS_GetEntryCount (S)) {
381
382         CodeEntry* L[9];
383         unsigned Len;
384
385         /* Get next entry */
386         L[0] = CS_GetEntry (S, I);
387
388         /* Check for the sequence */
389         if (L[0]->OPC == OP65_LDA                            &&
390             L[0]->AM == AM65_IMM                             &&
391             CS_GetEntries (S, L+1, I+1, 8)                   &&
392             L[1]->OPC == OP65_LDX                            &&
393             L[1]->AM == AM65_IMM                             &&
394             !CE_HasLabel (L[1])                              &&
395             L[2]->OPC == OP65_LDY                            &&
396             CE_IsConstImm (L[2])                             &&
397             !CE_HasLabel (L[2])                              &&
398             L[3]->OPC == OP65_CLC                            &&
399             !CE_HasLabel (L[3])                              &&
400             L[4]->OPC == OP65_ADC                            &&
401             L[4]->AM == AM65_ZP_INDY                         &&
402             !CE_HasLabel (L[4])                              &&
403             (L[5]->OPC == OP65_BCC || L[5]->OPC == OP65_JCC) &&
404             L[5]->JumpTo != 0                                &&
405             L[5]->JumpTo->Owner == L[7]                      &&
406             !CE_HasLabel (L[5])                              &&
407             L[6]->OPC == OP65_INX                            &&
408             !CE_HasLabel (L[6])                              &&
409             L[7]->OPC == OP65_LDY                            &&
410             CE_IsKnownImm (L[7], 0)                          &&
411             CE_IsCallTo (L[8], "ldauidx")                    &&
412             !CE_HasLabel (L[8])                              &&
413             /* Check the label last because this is quite costly */
414             (Len = strlen (L[0]->Arg)) > 3                   &&
415             L[0]->Arg[0] == '<'                              &&
416             L[0]->Arg[1] == '('                              &&
417             strlen (L[1]->Arg) == Len                        &&
418             L[1]->Arg[0] == '>'                              &&
419             memcmp (L[0]->Arg+1, L[1]->Arg+1, Len-1) == 0) {
420
421             CodeEntry* X;
422             char* Label;
423
424             /* Add the lda */
425             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[4]->Arg, 0, L[0]->LI);
426             CS_InsertEntry (S, X, I+3);
427
428             /* Add the tay */
429             X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, L[0]->LI);
430             CS_InsertEntry (S, X, I+4);
431
432             /* Add the ldx */
433             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[0]->LI);
434             CS_InsertEntry (S, X, I+5);
435
436             /* Add the lda */
437             Label = memcpy (xmalloc (Len-2), L[0]->Arg+2, Len-3);
438             Label[Len-3] = '\0';
439             X = NewCodeEntry (OP65_LDA, AM65_ABSY, Label, 0, L[0]->LI);
440             CS_InsertEntry (S, X, I+6);
441             xfree (Label);
442
443             /* Remove the old code */
444             CS_DelEntries (S, I, 2);
445             CS_DelEntries (S, I+5, 6);
446
447             /* Remember, we had changes */
448             ++Changes;
449
450         }
451
452         /* Next entry */
453         ++I;
454
455     }
456
457     /* Return the number of changes made */
458     return Changes;
459 }
460
461
462
463 unsigned OptPtrLoad5 (CodeSeg* S)
464 /* Search for the sequence:
465  *
466  *      clc
467  *      adc     xxx
468  *      bcc     L
469  *      inx
470  * L:   ldy     #$00
471  *      jsr     ldauidx
472  *
473  * and replace it by:
474  *
475  *      ldy     xxx
476  *      sta     ptr1
477  *      stx     ptr1+1
478  *      ldx     #$00
479  *      lda     (ptr1),y
480  */
481 {
482     unsigned Changes = 0;
483
484     /* Walk over the entries */
485     unsigned I = 0;
486     while (I < CS_GetEntryCount (S)) {
487
488         CodeEntry* L[6];
489
490         /* Get next entry */
491         L[0] = CS_GetEntry (S, I);
492
493         /* Check for the sequence */
494         if (L[0]->OPC == OP65_CLC                            &&
495             CS_GetEntries (S, L+1, I+1, 5)                   &&
496             L[1]->OPC == OP65_ADC                            &&
497             (L[1]->AM == AM65_ABS || L[1]->AM == AM65_ZP || L[1]->AM == AM65_IMM)    &&
498             (L[2]->OPC == OP65_BCC || L[2]->OPC == OP65_JCC) &&
499             L[2]->JumpTo != 0                                &&
500             L[2]->JumpTo->Owner == L[4]                      &&
501             L[3]->OPC == OP65_INX                            &&
502             L[4]->OPC == OP65_LDY                            &&
503             CE_IsKnownImm (L[4], 0)                          &&
504             CE_IsCallTo (L[5], "ldauidx")                    &&
505             !CS_RangeHasLabel (S, I+1, 3)                    &&
506             !CE_HasLabel (L[5])) {
507
508             CodeEntry* X;
509
510             /* We will create all the new stuff behind the current one so
511              * we keep the line references.
512              */
513             X = NewCodeEntry (OP65_LDY, L[1]->AM, L[1]->Arg, 0, L[0]->LI);
514             CS_InsertEntry (S, X, I+6);
515
516             /* sta ptr1 */
517             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI);
518             CS_InsertEntry (S, X, I+7);
519
520             /* stx ptr1+1 */
521             X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[0]->LI);
522             CS_InsertEntry (S, X, I+8);
523
524             /* ldx #$00 */
525             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[0]->LI);
526             CS_InsertEntry (S, X, I+9);
527
528             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[0]->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  *      lda     regbank+n
554  *      ldx     regbank+n+1
555  *      sta     regsave
556  *      stx     regsave+1
557  *      clc
558  *      adc     #$01
559  *      bcc     L0005
560  *      inx
561  * L:   sta     regbank+n
562  *      stx     regbank+n+1
563  *      lda     regsave
564  *      ldx     regsave+1
565  *      ldy     #$00
566  *      jsr     ldauidx
567  *
568  * and replace it by:
569  *
570  *      ldy     #$00
571  *      ldx     #$00
572  *      lda     (regbank+n),y
573  *      inc     regbank+n
574  *      bne     L1
575  *      inc     regbank+n+1
576  * L1:  tay                     <- only if flags are used
577  *
578  * This function must execute before OptPtrLoad7!
579  *
580  */
581 {
582     unsigned Changes = 0;
583
584     /* Walk over the entries */
585     unsigned I = 0;
586     while (I < CS_GetEntryCount (S)) {
587
588         CodeEntry* L[15];
589         unsigned Len;
590
591         /* Get next entry */
592         L[0] = CS_GetEntry (S, I);
593
594         /* Check for the sequence */
595         if (L[0]->OPC == OP65_LDA                               &&
596             L[0]->AM == AM65_ZP                                 &&
597             strncmp (L[0]->Arg, "regbank+", 8) == 0             &&
598             (Len = strlen (L[0]->Arg)) > 0                      &&
599             CS_GetEntries (S, L+1, I+1, 14)                     &&
600             !CS_RangeHasLabel (S, I+1, 7)                       &&
601             !CS_RangeHasLabel (S, I+9, 5)                       &&
602             L[1]->OPC == OP65_LDX                               &&
603             L[1]->AM == AM65_ZP                                 &&
604             strncmp (L[1]->Arg, L[0]->Arg, Len) == 0            &&
605             strcmp (L[1]->Arg+Len, "+1") == 0                   &&
606             L[2]->OPC == OP65_STA                               &&
607             L[2]->AM == AM65_ZP                                 &&
608             strcmp (L[2]->Arg, "regsave") == 0                  &&
609             L[3]->OPC == OP65_STX                               &&
610             L[3]->AM == AM65_ZP                                 &&
611             strcmp (L[3]->Arg, "regsave+1") == 0                &&
612             L[4]->OPC == OP65_CLC                               &&
613             L[5]->OPC == OP65_ADC                               &&
614             CE_IsKnownImm (L[5], 1)                             &&
615             L[6]->OPC == OP65_BCC                               &&
616             L[6]->JumpTo != 0                                   &&
617             L[6]->JumpTo->Owner == L[8]                         &&
618             L[7]->OPC == OP65_INX                               &&
619             L[8]->OPC == OP65_STA                               &&
620             L[8]->AM == AM65_ZP                                 &&
621             strcmp (L[8]->Arg, L[0]->Arg) == 0                  &&
622             L[9]->OPC == OP65_STX                               &&
623             L[9]->AM == AM65_ZP                                 &&
624             strcmp (L[9]->Arg, L[1]->Arg) == 0                  &&
625             L[10]->OPC == OP65_LDA                              &&
626             L[10]->AM == AM65_ZP                                &&
627             strcmp (L[10]->Arg, "regsave") == 0                 &&
628             L[11]->OPC == OP65_LDX                              &&
629             L[11]->AM == AM65_ZP                                &&
630             strcmp (L[11]->Arg, "regsave+1") == 0               &&
631             L[12]->OPC == OP65_LDY                              &&
632             CE_IsConstImm (L[12])                               &&
633             CE_IsCallTo (L[13], "ldauidx")) {
634
635             CodeEntry* X;
636             CodeLabel* Label;
637
638             /* Check if the instruction following the sequence uses the flags
639              * set by the load. If so, insert a test of the value in the
640              * accumulator.
641              */
642             if (CE_UseLoadFlags (L[14])) {
643                 X = NewCodeEntry (OP65_TAY, AM65_IMP, 0, 0, L[13]->LI);
644                 CS_InsertEntry (S, X, I+14);
645             }
646
647             /* Attach a label to L[14]. This may be either the just inserted
648              * instruction, or the one following the sequence.
649              */
650             Label = CS_GenLabel (S, L[14]);
651
652             /* ldy #$xx */
653             X = NewCodeEntry (OP65_LDY, AM65_IMM, L[12]->Arg, 0, L[12]->LI);
654             CS_InsertEntry (S, X, I+14);
655
656             /* ldx #$xx */
657             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[13]->LI);
658             CS_InsertEntry (S, X, I+15);
659
660             /* lda (regbank+n),y */
661             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[13]->LI);
662             CS_InsertEntry (S, X, I+16);
663
664             /* inc regbank+n */
665             X = NewCodeEntry (OP65_INC, AM65_ZP, L[0]->Arg, 0, L[5]->LI);
666             CS_InsertEntry (S, X, I+17);
667
668             /* bne ... */
669             X = NewCodeEntry (OP65_BNE, AM65_BRA, Label->Name, Label, L[6]->LI);
670             CS_InsertEntry (S, X, I+18);
671
672             /* inc regbank+n+1 */
673             X = NewCodeEntry (OP65_INC, AM65_ZP, L[1]->Arg, 0, L[7]->LI);
674             CS_InsertEntry (S, X, I+19);
675
676             /* Delete the old code */
677             CS_DelEntries (S, I, 14);
678
679             /* Remember, we had changes */
680             ++Changes;
681
682         }
683
684         /* Next entry */
685         ++I;
686
687     }
688
689     /* Return the number of changes made */
690     return Changes;
691 }
692
693
694
695 unsigned OptPtrLoad7 (CodeSeg* S)
696 /* Search for the sequence:
697  *
698  *      lda     zp
699  *      ldx     zp+1
700  *      ldy     xx
701  *      jsr     ldauidx
702  *
703  * and replace it by:
704  *
705  *      ldy     xx
706  *      ldx     #$00
707  *      lda     (zp),y
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[4];
717         unsigned Len;
718
719         /* Get next entry */
720         L[0] = CS_GetEntry (S, I);
721
722         /* Check for the sequence */
723         if (L[0]->OPC == OP65_LDA && L[0]->AM == AM65_ZP        &&
724             CS_GetEntries (S, L+1, I+1, 3)                      &&
725             !CS_RangeHasLabel (S, I+1, 3)                       &&
726             L[1]->OPC == OP65_LDX && L[1]->AM == AM65_ZP        &&
727             (Len = strlen (L[0]->Arg)) > 0                      &&
728             strncmp (L[0]->Arg, L[1]->Arg, Len) == 0            &&
729             strcmp (L[1]->Arg + Len, "+1") == 0                 &&
730             L[2]->OPC == OP65_LDY                               &&
731             CE_IsCallTo (L[3], "ldauidx")) {
732
733             CodeEntry* X;
734
735             /* ldx #$00 */
736             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[3]->LI);
737             CS_InsertEntry (S, X, I+3);
738
739             /* lda (zp),y */
740             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI);
741             CS_InsertEntry (S, X, I+4);
742
743             /* Remove the old code */
744             CS_DelEntry (S, I+5);
745             CS_DelEntries (S, I, 2);
746
747             /* Remember, we had changes */
748             ++Changes;
749
750         }
751
752         /* Next entry */
753         ++I;
754
755     }
756
757     /* Return the number of changes made */
758     return Changes;
759 }
760
761
762
763 unsigned OptPtrLoad8 (CodeSeg* S)
764 /* Search for the sequence:
765  *
766  *      lda     zp
767  *      ldx     zp+1
768  *      (anything that doesn't change a/x)
769  *      ldy     xx
770  *      jsr     ldauidx
771  *
772  * and replace it by:
773  *
774  *      lda     zp
775  *      ldx     zp+1
776  *      (anything that doesn't change a/x)
777  *      ldy     xx
778  *      ldx     #$00
779  *      lda     (zp),y
780  *
781  * Must execute before OptPtrLoad10!
782  */
783 {
784     unsigned Changes = 0;
785     unsigned I;
786
787     /* Generate register info */
788     CS_GenRegInfo (S);
789
790     /* Walk over the entries */
791     I = 0;
792     while (I < CS_GetEntryCount (S)) {
793
794         CodeEntry* L[5];
795         unsigned Len;
796
797         /* Get next entry */
798         L[0] = CS_GetEntry (S, I);
799
800         /* Check for the sequence */
801         if (L[0]->OPC == OP65_LDA && L[0]->AM == AM65_ZP        &&
802             CS_GetEntries (S, L+1, I+1, 4)                      &&
803             !CS_RangeHasLabel (S, I+1, 4)                       &&
804             L[1]->OPC == OP65_LDX && L[1]->AM == AM65_ZP        &&
805             (Len = strlen (L[0]->Arg)) > 0                      &&
806             strncmp (L[0]->Arg, L[1]->Arg, Len) == 0            &&
807             strcmp (L[1]->Arg + Len, "+1") == 0                 &&
808             (L[2]->Chg & REG_AX) == 0                           &&
809             L[3]->OPC == OP65_LDY                               &&
810             CE_IsCallTo (L[4], "ldauidx")) {
811
812             CodeEntry* X;
813
814             /* ldx #$00 */
815             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[3]->LI);
816             CS_InsertEntry (S, X, I+5);
817
818             /* lda (zp),y */
819             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI);
820             CS_InsertEntry (S, X, I+6);
821
822             /* Remove the old code */
823             CS_DelEntry (S, I+4);
824
825             /* Remember, we had changes */
826             ++Changes;
827
828         }
829
830         /* Next entry */
831         ++I;
832
833     }
834
835     /* Free the register info */
836     CS_FreeRegInfo (S);
837
838     /* Return the number of changes made */
839     return Changes;
840 }
841
842
843
844 unsigned OptPtrLoad9 (CodeSeg* S)
845 /* Search for the sequence:
846  *
847  *      lda     zp
848  *      ldx     zp+1
849  *      ldy     xx
850  *      jsr     ldaxidx
851  *
852  * and replace it by:
853  *
854  *      ldy     xx
855  *      lda     (zp),y
856  *      tax
857  *      dey
858  *      lda     (zp),y
859  */
860 {
861     unsigned Changes = 0;
862
863     /* Walk over the entries */
864     unsigned I = 0;
865     while (I < CS_GetEntryCount (S)) {
866
867         CodeEntry* L[4];
868         unsigned Len;
869
870         /* Get next entry */
871         L[0] = CS_GetEntry (S, I);
872
873         /* Check for the sequence */
874         if (L[0]->OPC == OP65_LDA && L[0]->AM == AM65_ZP        &&
875             CS_GetEntries (S, L+1, I+1, 3)                      &&
876             !CS_RangeHasLabel (S, I+1, 3)                       &&
877             L[1]->OPC == OP65_LDX && L[1]->AM == AM65_ZP        &&
878             (Len = strlen (L[0]->Arg)) > 0                      &&
879             strncmp (L[0]->Arg, L[1]->Arg, Len) == 0            &&
880             strcmp (L[1]->Arg + Len, "+1") == 0                 &&
881             L[2]->OPC == OP65_LDY                               &&
882             CE_IsCallTo (L[3], "ldaxidx")) {
883
884             CodeEntry* X;
885
886             /* lda (zp),y */
887             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI);
888             CS_InsertEntry (S, X, I+4);
889
890             /* tax */
891             X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[3]->LI);
892             CS_InsertEntry (S, X, I+5);
893
894             /* dey */
895             X = NewCodeEntry (OP65_DEY, AM65_IMP, 0, 0, L[3]->LI);
896             CS_InsertEntry (S, X, I+6);
897
898             /* lda (zp),y */
899             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, L[0]->Arg, 0, L[3]->LI);
900             CS_InsertEntry (S, X, I+7);
901
902             /* Remove the old code */
903             CS_DelEntry (S, I+3);
904             CS_DelEntries (S, I, 2);
905
906             /* Remember, we had changes */
907             ++Changes;
908
909         }
910
911         /* Next entry */
912         ++I;
913
914     }
915
916     /* Return the number of changes made */
917     return Changes;
918 }
919
920
921
922 unsigned OptPtrLoad10 (CodeSeg* S)
923 /* Search for the sequence
924  *
925  *      ldy     ...
926  *      jsr     ldauidx
927  *
928  * and replace it by:
929  *
930  *      ldy     ...
931  *      stx     ptr1+1
932  *      sta     ptr1
933  *      ldx     #$00
934  *      lda     (ptr1),y
935  *
936  * This step must be executed *after* OptPtrLoad1!
937  */
938 {
939     unsigned Changes = 0;
940
941     /* Walk over the entries */
942     unsigned I = 0;
943     while (I < CS_GetEntryCount (S)) {
944
945         CodeEntry* L[2];
946
947         /* Get next entry */
948         L[0] = CS_GetEntry (S, I);
949
950         /* Check for the sequence */
951         if (L[0]->OPC == OP65_LDY               &&
952             CS_GetEntries (S, L+1, I+1, 1)      &&
953             CE_IsCallTo (L[1], "ldauidx")       &&
954             !CE_HasLabel (L[1])) {
955
956             CodeEntry* X;
957
958             /* Store the high byte */
959             X = NewCodeEntry (OP65_STA, AM65_ZP, "ptr1", 0, L[0]->LI);
960             CS_InsertEntry (S, X, I+1);
961
962             /* Store the low byte */
963             X = NewCodeEntry (OP65_STX, AM65_ZP, "ptr1+1", 0, L[0]->LI);
964             CS_InsertEntry (S, X, I+2);
965
966             /* Delete the call to ldauidx */
967             CS_DelEntry (S, I+3);
968
969             /* Load the high and low byte */
970             X = NewCodeEntry (OP65_LDX, AM65_IMM, "$00", 0, L[0]->LI);
971             CS_InsertEntry (S, X, I+3);
972             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "ptr1", 0, L[0]->LI);
973             CS_InsertEntry (S, X, I+4);
974
975             /* Remember, we had changes */
976             ++Changes;
977
978         }
979
980         /* Next entry */
981         ++I;
982
983     }
984
985     /* Return the number of changes made */
986     return Changes;
987 }
988
989
990