]> git.sur5r.net Git - cc65/blob - src/cc65/coptadd.c
Some function renaming.
[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  *      clc
67  *      ldy     #yy-3
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             /* clc */
112             X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[5]->LI);
113             CS_InsertEntry (S, X, I+2);
114
115             /* ldy #yy-3 */
116             Arg = MakeHexArg (L[3]->Num - 3);
117             X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, L[4]->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  *      lda     xxx
294  *      ldx     yyy
295  *      jsr     tosaddax
296  *
297  * and replace it by
298  *
299  *      clc
300  *      adc     xxx
301  *      pha
302  *      txa
303  *      adc     yyy
304  *      tax
305  *      pla
306  */
307 {
308     unsigned Changes = 0;
309
310     /* Walk over the entries */
311     unsigned I = 0;
312     while (I < CS_GetEntryCount (S)) {
313
314         CodeEntry* L[4];
315
316         /* Get next entry */
317         L[0] = CS_GetEntry (S, I);
318
319         /* Check for the sequence */
320         if (CE_IsCallTo (L[0], "pushax")                        &&
321             CS_GetEntries (S, L+1, I+1, 3)                      &&
322             !CS_RangeHasLabel (S, I+1, 3)                       &&
323             L[1]->OPC == OP65_LDA                               &&
324             (L[1]->AM == AM65_ABS || L[1]->AM == AM65_ZP)       &&
325             L[2]->OPC == OP65_LDX                               &&
326             (L[2]->AM == AM65_ABS || L[2]->AM == AM65_ZP)       &&
327             CE_IsCallTo (L[3], "tosaddax")) {
328
329             CodeEntry* X;
330
331             /* Insert new code behind the sequence */
332             X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[3]->LI);
333             CS_InsertEntry (S, X, I+4);
334
335             /* adc xxx */
336             X = NewCodeEntry (OP65_ADC, L[1]->AM, L[1]->Arg, 0, L[3]->LI);
337             CS_InsertEntry (S, X, I+5);
338
339             /* pha */
340             X = NewCodeEntry (OP65_PHA, AM65_IMP, 0, 0, L[3]->LI);
341             CS_InsertEntry (S, X, I+6);
342
343             /* txa */
344             X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, L[3]->LI);
345             CS_InsertEntry (S, X, I+7);
346
347             /* adc yyy */
348             X = NewCodeEntry (OP65_ADC, L[2]->AM, L[2]->Arg, 0, L[3]->LI);
349             CS_InsertEntry (S, X, I+8);
350
351             /* tax */
352             X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[3]->LI);
353             CS_InsertEntry (S, X, I+9);
354
355             /* pla */
356             X = NewCodeEntry (OP65_PLA, AM65_IMP, 0, 0, L[3]->LI);
357             CS_InsertEntry (S, X, I+10);
358
359             /* Delete the old code */
360             CS_DelEntries (S, I, 4);
361
362             /* Remember, we had changes */
363             ++Changes;
364
365         }
366
367         /* Next entry */
368         ++I;
369
370     }
371
372     /* Return the number of changes made */
373     return Changes;
374 }
375
376
377
378 unsigned OptAdd4 (CodeSeg* S)
379 /* Search for a call to incaxn and replace it by an 8 bit add if the X register
380  * is not used later.
381  */
382 {
383     unsigned Changes = 0;
384
385     /* Walk over the entries */
386     unsigned I = 0;
387     while (I < CS_GetEntryCount (S)) {
388
389         CodeEntry* E;
390
391         /* Get next entry */
392         E = CS_GetEntry (S, I);
393
394         /* Check for the sequence */
395         if (E->OPC == OP65_JSR                          &&
396             strncmp (E->Arg, "incax", 5) == 0           &&
397             IsDigit (E->Arg[5])                         &&
398             E->Arg[6] == '\0'                           &&
399             !RegXUsed (S, I+1)) {
400
401             CodeEntry* X;
402             const char* Arg;
403
404             /* Insert new code behind the sequence */
405             X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, E->LI);
406             CS_InsertEntry (S, X, I+1);
407
408             Arg = MakeHexArg (E->Arg[5] - '0');
409             X = NewCodeEntry (OP65_ADC, AM65_IMM, Arg, 0, E->LI);
410             CS_InsertEntry (S, X, I+2);
411
412             /* Delete the old code */
413             CS_DelEntry (S, I);
414
415             /* Remember, we had changes */
416             ++Changes;
417
418         }
419
420         /* Next entry */
421         ++I;
422
423     }
424
425     /* Return the number of changes made */
426     return Changes;
427 }
428
429
430
431 unsigned OptAdd5 (CodeSeg* S)
432 /* Search for the sequence
433  *
434  *      adc     ...
435  *      bcc     L
436  *      inx
437  * L:
438  *
439  * and remove the handling of the high byte if X is not used later.
440  */
441 {
442     unsigned Changes = 0;
443
444     /* Walk over the entries */
445     unsigned I = 0;
446     while (I < CS_GetEntryCount (S)) {
447
448         CodeEntry* L[3];
449
450         /* Get next entry */
451         CodeEntry* E = CS_GetEntry (S, I);
452
453         /* Check for the sequence */
454         if (E->OPC == OP65_ADC                               &&
455             CS_GetEntries (S, L, I+1, 3)                     &&
456             (L[0]->OPC == OP65_BCC || L[0]->OPC == OP65_JCC) &&
457             L[0]->JumpTo != 0                                &&
458             !CE_HasLabel (L[0])                              &&
459             L[1]->OPC == OP65_INX                            &&
460             !CE_HasLabel (L[1])                              &&
461             L[0]->JumpTo->Owner == L[2]                      &&
462             !RegXUsed (S, I+3)) {
463
464             /* Remove the bcs/dex */
465             CS_DelEntries (S, I+1, 2);
466
467             /* Remember, we had changes */
468             ++Changes;
469
470         }
471
472         /* Next entry */
473         ++I;
474
475     }
476
477     /* Return the number of changes made */
478     return Changes;
479 }
480
481
482