]> git.sur5r.net Git - cc65/blob - src/cc65/coptadd.c
Additional pointer load optimization
[cc65] / src / cc65 / coptadd.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 coptadd.c                                 */
4 /*                                                                           */
5 /*                        Optimize addition sequences                        */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2001-2002 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@cc65.org                                                 */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <ctype.h>
37
38 /* cc65 */
39 #include "codeent.h"
40 #include "codeinfo.h"
41 #include "coptadd.h"
42
43
44
45 /*****************************************************************************/
46 /*                            Optimize additions                             */
47 /*****************************************************************************/
48
49
50
51 unsigned OptAdd1 (CodeSeg* S)
52 /* Search for the sequence
53  *
54  *      ldy     #xx
55  *      jsr     ldaxysp
56  *      jsr     pushax
57  *      ldy     #yy
58  *      jsr     ldaxysp
59  *      jsr     tosaddax
60  *
61  * and replace it by:
62  *
63  *      ldy     #xx-1
64  *      lda     (sp),y
65  *      clc
66  *      ldy     #yy-3
67  *      adc     (sp),y
68  *      pha
69  *      ldy     #xx
70  *      lda     (sp),y
71  *      ldy     #yy-2
72  *      adc     (sp),y
73  *      tax
74  *      pla
75  */
76 {
77     unsigned Changes = 0;
78
79     /* Walk over the entries */
80     unsigned I = 0;
81     while (I < CS_GetEntryCount (S)) {
82
83         CodeEntry* L[6];
84
85         /* Get next entry */
86         L[0] = CS_GetEntry (S, I);
87
88         /* Check for the sequence */
89         if (L[0]->OPC == OP65_LDY            &&
90             CE_KnownImm (L[0])               &&
91             !CS_RangeHasLabel (S, I+1, 5)    &&
92             CS_GetEntries (S, L+1, I+1, 5)   &&
93             CE_IsCallTo (L[1], "ldaxysp")    &&
94             CE_IsCallTo (L[2], "pushax")     &&
95             L[3]->OPC == OP65_LDY            &&
96             CE_KnownImm (L[3])               &&
97             CE_IsCallTo (L[4], "ldaxysp")    &&
98             CE_IsCallTo (L[5], "tosaddax")) {
99
100             CodeEntry* X;
101             const char* Arg;
102
103             /* Correct the stack of the first Y register load */
104             CE_SetNumArg (L[0], L[0]->Num - 1);
105
106             /* lda (sp),y */
107             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI);
108             CS_InsertEntry (S, X, I+1);
109
110             /* clc */
111             X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[5]->LI);
112             CS_InsertEntry (S, X, I+2);
113
114             /* ldy #yy-3 */
115             Arg = MakeHexArg (L[3]->Num - 3);
116             X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[4]->LI);
117             CS_InsertEntry (S, X, I+3);
118
119             /* adc (sp),y */
120             X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[5]->LI);
121             CS_InsertEntry (S, X, I+4);
122
123             /* pha */
124             X = NewCodeEntry (OP65_PHA, AM65_IMP, 0, 0, L[5]->LI);
125             CS_InsertEntry (S, X, I+5);
126
127             /* ldy #xx (beware: L[0] has changed) */
128             Arg = MakeHexArg (L[0]->Num + 1);
129             X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[1]->LI);
130             CS_InsertEntry (S, X, I+6);
131
132             /* lda (sp),y */
133             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI);
134             CS_InsertEntry (S, X, I+7);
135
136             /* ldy #yy-2 */
137             Arg = MakeHexArg (L[3]->Num - 2);
138             X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[4]->LI);
139             CS_InsertEntry (S, X, I+8);
140
141             /* adc (sp),y */
142             X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[5]->LI);
143             CS_InsertEntry (S, X, I+9);
144
145             /* tax */
146             X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[5]->LI);
147             CS_InsertEntry (S, X, I+10);
148
149             /* pla */
150             X = NewCodeEntry (OP65_PLA, AM65_IMP, 0, 0, L[5]->LI);
151             CS_InsertEntry (S, X, I+11);
152
153             /* Delete the old code */
154             CS_DelEntries (S, I+12, 5);
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 OptAdd2 (CodeSeg* S)
173 /* Search for the sequence
174  *
175  *      ldy     #xx
176  *      jsr     ldaxysp
177  *      ldy     #yy
178  *      jsr     addeqysp
179  *
180  * and replace it by:
181  *
182  *      ldy     #xx-1
183  *      lda     (sp),y
184  *      ldy     #yy
185  *      clc
186  *      adc     (sp),y
187  *      sta     (sp),y
188  *      ldy     #xx
189  *      lda     (sp),y
190  *      ldy     #yy+1
191  *      adc     (sp),y
192  *      sta     (sp),y
193  *
194  * provided that a/x is not used later.
195  */
196 {
197     unsigned Changes = 0;
198
199     /* Walk over the entries */
200     unsigned I = 0;
201     while (I < CS_GetEntryCount (S)) {
202
203         CodeEntry* L[4];
204
205         /* Get next entry */
206         L[0] = CS_GetEntry (S, I);
207
208         /* Check for the sequence */
209         if (L[0]->OPC == OP65_LDY               &&
210             CE_KnownImm (L[0])                  &&
211             !CS_RangeHasLabel (S, I+1, 3)       &&
212             CS_GetEntries (S, L+1, I+1, 3)      &&
213             CE_IsCallTo (L[1], "ldaxysp")       &&
214             L[2]->OPC == OP65_LDY               &&
215             CE_KnownImm (L[2])                  &&
216             CE_IsCallTo (L[3], "addeqysp")      &&
217             (GetRegInfo (S, I+4, REG_AX) & REG_AX) == 0) {
218
219             /* Insert new code behind the addeqysp */
220             const char* Arg;
221             CodeEntry* X;
222
223             /* ldy     #xx-1 */
224             Arg = MakeHexArg (L[0]->Num-1);
225             X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[0]->LI);
226             CS_InsertEntry (S, X, I+4);
227
228             /* lda     (sp),y */
229             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI);
230             CS_InsertEntry (S, X, I+5);
231
232             /* ldy     #yy */
233             X = NewCodeEntry (OP65_LDY, AM65_IMM, L[2]->Arg, 0, L[2]->LI);
234             CS_InsertEntry (S, X, I+6);
235
236             /* clc */
237             X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[3]->LI);
238             CS_InsertEntry (S, X, I+7);
239
240             /* adc     (sp),y */
241             X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[3]->LI);
242             CS_InsertEntry (S, X, I+8);
243
244             /* sta     (sp),y */
245             X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "sp", 0, L[3]->LI);
246             CS_InsertEntry (S, X, I+9);
247
248             /* ldy     #xx */
249             X = NewCodeEntry (OP65_LDY, AM65_IMM, L[0]->Arg, 0, L[0]->LI);
250             CS_InsertEntry (S, X, I+10);
251
252             /* lda     (sp),y */
253             X = NewCodeEntry (OP65_LDA, AM65_ZP_INDY, "sp", 0, L[1]->LI);
254             CS_InsertEntry (S, X, I+11);
255
256             /* ldy     #yy+1 */
257             Arg = MakeHexArg (L[2]->Num+1);
258             X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[2]->LI);
259             CS_InsertEntry (S, X, I+12);
260
261             /* adc     (sp),y */
262             X = NewCodeEntry (OP65_ADC, AM65_ZP_INDY, "sp", 0, L[3]->LI);
263             CS_InsertEntry (S, X, I+13);
264
265             /* sta     (sp),y */
266             X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, "sp", 0, L[3]->LI);
267             CS_InsertEntry (S, X, I+14);
268
269             /* Delete the old code */
270             CS_DelEntries (S, I, 4);
271
272             /* Remember, we had changes */
273             ++Changes;
274
275         }
276
277         /* Next entry */
278         ++I;
279
280     }
281
282     /* Return the number of changes made */
283     return Changes;
284 }
285
286
287
288 unsigned OptAdd3 (CodeSeg* S)
289 /* Search for the sequence
290  *
291  *      jsr     pushax
292  *      lda     xxx
293  *      ldx     yyy
294  *      jsr     tosaddax
295  *
296  * and replace it by
297  *
298  *      clc
299  *      adc     xxx
300  *      pha
301  *      txa
302  *      adc     yyy
303  *      tax
304  *      pla
305  */
306 {
307     unsigned Changes = 0;
308
309     /* Walk over the entries */
310     unsigned I = 0;
311     while (I < CS_GetEntryCount (S)) {
312
313         CodeEntry* L[4];
314
315         /* Get next entry */
316         L[0] = CS_GetEntry (S, I);
317
318         /* Check for the sequence */
319         if (CE_IsCallTo (L[0], "pushax")                        &&
320             CS_GetEntries (S, L+1, I+1, 3)                      &&
321             !CS_RangeHasLabel (S, I+1, 3)                       &&
322             L[1]->OPC == OP65_LDA                               &&
323             (L[1]->AM == AM65_ABS || L[1]->AM == AM65_ZP)       &&
324             L[2]->OPC == OP65_LDX                               &&
325             (L[2]->AM == AM65_ABS || L[2]->AM == AM65_ZP)       &&
326             CE_IsCallTo (L[3], "tosaddax")) {
327
328             CodeEntry* X;
329
330             /* Insert new code behind the sequence */
331             X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[3]->LI);
332             CS_InsertEntry (S, X, I+4);
333
334             /* adc xxx */
335             X = NewCodeEntry (OP65_ADC, L[1]->AM, L[1]->Arg, 0, L[3]->LI);
336             CS_InsertEntry (S, X, I+5);
337
338             /* pha */
339             X = NewCodeEntry (OP65_PHA, AM65_IMP, 0, 0, L[3]->LI);
340             CS_InsertEntry (S, X, I+6);
341
342             /* txa */
343             X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, L[3]->LI);
344             CS_InsertEntry (S, X, I+7);
345
346             /* adc yyy */
347             X = NewCodeEntry (OP65_ADC, L[2]->AM, L[2]->Arg, 0, L[3]->LI);
348             CS_InsertEntry (S, X, I+8);
349
350             /* tax */
351             X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[3]->LI);
352             CS_InsertEntry (S, X, I+9);
353
354             /* pla */
355             X = NewCodeEntry (OP65_PLA, AM65_IMP, 0, 0, L[3]->LI);
356             CS_InsertEntry (S, X, I+10);
357
358             /* Delete the old code */
359             CS_DelEntries (S, I, 4);
360
361             /* Remember, we had changes */
362             ++Changes;
363
364         }
365
366         /* Next entry */
367         ++I;
368
369     }
370
371     /* Return the number of changes made */
372     return Changes;
373 }
374
375
376
377 unsigned OptAdd4 (CodeSeg* S)
378 /* Search for a call to incaxn and replace it by an 8 bit add if the X register
379  * is not used later.
380  */
381 {
382     unsigned Changes = 0;
383
384     /* Walk over the entries */
385     unsigned I = 0;
386     while (I < CS_GetEntryCount (S)) {
387
388         CodeEntry* E;
389
390         /* Get next entry */
391         E = CS_GetEntry (S, I);
392
393         /* Check for the sequence */
394         if (E->OPC == OP65_JSR                          &&
395             strncmp (E->Arg, "incax", 5) == 0           &&
396             isdigit (E->Arg[5])                         &&
397             E->Arg[6] == '\0'                           &&
398             !RegXUsed (S, I+1)) {
399
400             CodeEntry* X;
401             const char* Arg;
402
403             /* Insert new code behind the sequence */
404             X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, E->LI);
405             CS_InsertEntry (S, X, I+1);
406
407             Arg = MakeHexArg (E->Arg[5] - '0');
408             X = NewCodeEntry (OP65_ADC, AM65_IMM, Arg, 0, E->LI);
409             CS_InsertEntry (S, X, I+2);
410
411             /* Delete the old code */
412             CS_DelEntry (S, I);
413
414             /* Remember, we had changes */
415             ++Changes;
416
417         }
418
419         /* Next entry */
420         ++I;
421
422     }
423
424     /* Return the number of changes made */
425     return Changes;
426 }
427
428
429
430 unsigned OptAdd5 (CodeSeg* S)
431 /* Search for the sequence
432  *
433  *      adc     ...
434  *      bcc     L
435  *      inx
436  * L:
437  *
438  * and remove the handling of the high byte if X is not used later.
439  */
440 {
441     unsigned Changes = 0;
442
443     /* Walk over the entries */
444     unsigned I = 0;
445     while (I < CS_GetEntryCount (S)) {
446
447         CodeEntry* L[3];
448
449         /* Get next entry */
450         CodeEntry* E = CS_GetEntry (S, I);
451
452         /* Check for the sequence */
453         if (E->OPC == OP65_ADC                               &&
454             CS_GetEntries (S, L, I+1, 3)                     &&
455             (L[0]->OPC == OP65_BCC || L[0]->OPC == OP65_JCC) &&
456             L[0]->JumpTo != 0                                &&
457             !CE_HasLabel (L[0])                              &&
458             L[1]->OPC == OP65_INX                            &&
459             !CE_HasLabel (L[1])                              &&
460             L[0]->JumpTo->Owner == L[2]                      &&
461             !RegXUsed (S, I+3)) {
462
463             /* Remove the bcs/dex */
464             CS_DelEntries (S, I+1, 2);
465
466             /* Remember, we had changes */
467             ++Changes;
468
469         }
470
471         /* Next entry */
472         ++I;
473
474     }
475
476     /* Return the number of changes made */
477     return Changes;
478 }
479
480
481