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